PDA

View Full Version : سمافورها در C#



Nilofar_Abi
دوشنبه 09 آذر 1388, 17:33 عصر
سلام.
لطفا راجع به نحوه نوشتن سمافورها در C# منو راهنمایی کنید .
میخام پروژه سیستم عامل بنویسم ( مشکل شام خوردن فیلسوف ها )
خیلی تو وب گشتم اما همه انگلیسی بود و متوجه نشدم.

mosi_asgari
دوشنبه 09 آذر 1388, 23:49 عصر
سلام

شما باید با مباحث MultiThreading در C# خوب آشنا باشید تا بتوانید فیلسوف ها را شبیه سازی کنید.

کلاسی داریم در .Net به نام Semaphore در فضای نامی System.Threading. شما در این کلاس می توانید تعیین کنید که چند تا Thread همزمان می توانند وارد ناحیه بحرانی شوند.
مثلا اگر بخواهید بگید که همزمان 3 نخ (Thread) می توانند وارد ناحیه بحرانی شوند باید از کد زیر استفاده کنید :


Semaphore s=new Semaphore(3,3);

معنی پارامتر دوم سازنده این است که ماکزیمم 3 نخ همزمان می توانند وارد ناحیه بحرانی شما شوند و معنی پارامتر اول این است که مقدار فعلی شمارنده Semaphor سه است یعنی هنوز نخی وارد ناحیه بحرانی نشده است.هر وقت که نخی وارد ناحیه بحرانی شود شما باید از متد WaitOne استفاده کنید که این متد از مقدار فعلی شمارنده یکی کم می کند یعنی می شود 2.هر بار که شما از WaitOne استفاده کنید یکی از شمارنده شما کم می شود تا زمانی که شمارنده شما صفر شود. اگر صفر شود Semaphore اجازه نمیدهد که هیچ نخی وارد ناحیه بحرانی شود و تمامی نخ ها را بلاک می کند و اجازه دسترسی نمی دهد. همچنین اگر نخی کارش با ناحیه بحرانی به پایان رسید شما باید از متد Release کلاس Semaphore استفاده کنید که باعث می شود به شمارنده شما یکی اضافه شود.

برای نوشتن برنامه فیلسوف ها هم شما باید از این کلاس استفاده کنید.فیلسوف ها را هم باید با یک Thread شبیه سازی کنید.

اگر دقیقا بگی کجای برنامت مشکل داری بهتر می توانم کمکت کنم.

یا علی.

mtss92
سه شنبه 10 آذر 1388, 13:11 عصر
سلام
با تشکر از mosi_asgari در مورد پاسخ خوبت
لطفا یک مثال کوچک در مورد سمافور ها و ترد ها در C# بذار
در ضمن منبع فارسی در مورد سمافورها پیدا نکردم یا اگه هست برای ما مبتدی ها خیلی سنگینه:ناراحت:
بازم ممنون

mosi_asgari
سه شنبه 10 آذر 1388, 16:32 عصر
با سلام

بنا به درخواست شما دوستان مطالبی مقدماتی را در مورد به کارگیری Thread ها در C# پست می کنم.

با استفاده از کلاس Thread در فضای نامی System.Threading شما می توانید برنامه های چند نخی را به راحتی ایجاد کنید. وظیفه کلاس Thread این است که قطعه کدی که شما مشخص می کنید را در پس زمینه اجرا کند. به طور کلی یک پروسس ( که همان برنامه شما است ) می تواند یک یا چند Thread را برای اجرا ایجاد کند. در نتیجه برنامه شما می تواند چندین کار را که از همدیگر مستقل هستند را به صورت همزمان انجام دهد. مثلا در حالی که دارد یک فرمول پیچیده ریاضی را حل می کند می تواند در همان لحظه به عنوان مثال به دیتابیس وصل شود و یک query را روی این دیتابیس اجرا کند.

قطعه کدی که Thread باید ایجاد کند همان متدی است که همه شما با آن آشنا هستید. یعنی شما باید به Thread یک متد بدهید تا برای شما اجرا کند. اما هر متدی را نمی توانید بدهید! یعنی متد شما باید یک امضای مشخص داشته باشد. Thread می تواند تنها متدی را اجرا کند که پارامتر ندارد و هیچ مقداری را هم بر نگرداند یعنی مثلا به صورت زیر باشد :


void DoSomthing();

خوب ، حالا .Net باید چه مکانیزمی داشته باشد تا اجازه ندهد که شما یک متد غیر مجاز را به Thread بدهید؟ برای گارانتی کردن این موضوع .Net از delegate استفاده میکند. delegate راهی است که می توان امضای متد را مشخص کرد. مثلا برای مشخص کردن متد هایی که نه پارامتر می گیرند نه مقداری را برمی گردانند باید از delegate به صورت زیر استفاده کرد :

public delegate void YourDelegateName();

می بینید که راحت است و بسیار شبیه تعریف متد می باشد با این تفاوت که از کلمه کلیدی delegate استفاده می کند و بدنه هم ندارد. در تعریف بالا YourDelegateName نامی است اختیاری که شما به delegate خود میدهید و در برنامه از آن استفاده میکنید.

خوب به سراغ کلاس Thread خودمان برگردیم. قرار بود که یک متد بدهیم به کلاس Thread و آقای Thread برای ما اجرا کند.ما باید این متد را در سازنده کلاس Thread بدهیم به صورت زیر :


Thread t =new Thread(MyMethod);

public void MyMethod()
{
// کد شما در این متد قرار می گیرد
}

بعد از این کار شما باید Thread خود را start کنید تا کد شما را اجرا کند به این صورت :


t.Start();

و کار تمام است! تبریک می گویم شما اولین برنامه چند نخی خود را نوشتید!

نگاهی به جزئیات کار :
وقتی شما نام متد خود را در سازنده Thread دادید و برنامه شما بدرستی اجرا شد علت آن است که یکی از سازنده های Thread به صورت زیر است :


public Thread(
ThreadStart (http://barnamenevis.org/forum/4bd42707-e766-2576-f7c6-c8b2375ce996.htm) start
)

یعنی سازنده انتظار دارد که شما شئی را به آن پاس کنید که از جنس ThreadStart باشد اما شما که تنها نام یک متد را به آن دادید علت چیست که برنامه شما درست اجرا می شود؟
علت این است که ThreadStart یک delegate است که اشاره به متدهای بدون پارامتر و بدون مقدار برگشتی میکند برای همین است که کامپایلر این روش را ایراد نمی گیرد یعنی ThreadStart به صورت زیر تعریف شده است :


public delegate void ThreadStart();

روش دیگر برای پاس کردن یک متد به Thread این است که به صورت صریح از خود delegate
استفاده کنید یعنی به صورت زیر :


ThreadStart threadDelegate = new ThreadStart(MyMethod);

Thread t = new Thread(threadDelegate);




نتیجه گیری :

شما در اینجا با کلاس Thread آشنا شدید و نحوه پاس کردن یک متد بدون پارامتر را به Thread یاد گرفتید. سازنده Thread می تواند متد با پارامتر را هم بگیرد که برای فرستادن اطلاعات به Thread استفاده می شود. اگر ببینم که دوستان استقبال می کنند این مطالب را ادامه می دهم.

یا علی

Nilofar_Abi
سه شنبه 10 آذر 1388, 17:36 عصر
اول سلام
دوما اینکه خیلی ممنون به خا طر توضیحات خوبت
با راهنمایی هات تونستم یک برنامه خیلی کوچیک با ترد بنویسم حالا میخام ترد ها رو متوقف کنم چند تا متد پیدا کردم مثل sleep و join و lock .
با متد sleep تونستم کار کنم . اما متد lock برام نامفهوم بود
لطفا نحوه کار این متدو برام توضیح بده

mosi_asgari
چهارشنبه 11 آذر 1388, 00:36 صبح
چند تا متد پیدا کردم مثل sleep و join و lock .
با متد sleep تونستم کار کنم . اما متد lock برام نامفهوم بود
لطفا نحوه کار این متدو برام توضیح بده

با سلام و عرض ادب و احترام به شما دوست عزیز

کلاس Thread متدی به نام lock ندارد!!! C#‎‎ یک کلمه کلیدی دارد به نام lock.

مهمترین کار در مبحث چند نخی همگام سازی دسترسی به یک منبع مشترک است. مثلا اگر شما دو Thread داشته باشید که کار خواندن و نوشتن روی یک متغیر مشترک را انجام می دهند شما باید راهی را برای همگام سازی این عملیات پیدا کنید یعنی اینکه یک Thread نتواند این متغیر مشترک را بخواند یا بنویسد وقتی که Threadدیگر در حال نوشتن در این متغیر است.
اگر شما این کار رانکنید منجر به نتایج ناخواسته و غلط در برنامه شما میشود.

حالا ساده ترین راه برای همگام سازی Thread ها استفاده از کلمه کلیدی lock در C#‎‎ است.

از lock موقعی باید استفاده کنید که قسمتی از کد شما باید به صورت atomic توسط یک Thread اجرا شود. در این حال Thread های دیگه حق ورود به ناحیه ای که با lock مشخص شده باشد را ندارند در صورتی که یک Thread قبلا وارد این ناحیه شده است و هنوز داخل آن است.

lock یک آبجکت غیر null را می گیرد ( دقت کنید که object شما نباید null باشد و همینطور object شما باید RefrenceType باشد نه ValueType) . این object باید توسط تمامی Thread ها قابل دسترس باشد. معمولا یکی از فیلد های داخل کلاس را
برای این کار در نظر میگیرند. نوع این object مهم نیست برای همین معمولا از نوع System.Object استفاده می کنند.

مثال : دو Thread داریم یک کار مشترک را انجام می دهند و یک متغیر مشترک به نام counter هم دارند :


Thread t1 = new Thread(Job);
Thread t2 = new Thread(Job);

t1.Start();
t2.Start();


// این همان object برای lock است.
Object obj = new Object();

// این مثلا همان منبع مشترک ما بین این دو نخ است
int counter=0;

// این متد را هر دو نخ با هم همزمان انجام می دهند.پس باید از لاک برای خواندن و
// و نوشتن متغیر مشترک بین آنها استفاده کرد.
public void Job()
}
// شروع متد Job

// یکسری کار

lock(obj)
{
// نوشتن متغیر مشترک
counter++;
}

//یکسری کار

lock(obj)
{
// خواندن متغیر مشترک
a = counter;
}

// یکسری کار

// پایان متد Job
{

امیدورام یک چیزهایی یاد گرفته باشید.ما رو هم از دعای خیرتون محروم نکنید.

یا علی.

Nilofar_Abi
پنج شنبه 12 آذر 1388, 13:54 عصر
سلام

:تشویق:
ممنون از توضیحاتت .
اونارو خوندم خیلی عالی بود مطمئنا بدردم میخوره
حالا باید برم داخله C# تست کنم اگه مشکلی داشتم ازت می پرسم .
mer30
:تشویق:

zo_se1386
جمعه 04 دی 1388, 12:11 عصر
سلام

اول بگم که از همه ممنونم مخصوصا جناب mosi_asgari به خاطر مطالب مفیدشون
من برای اولین بار می خوام با c# ،برنامه بنویسم .
دستوراتی رو که گفتید رو نمیدونم کجای برنامه باید بنویسم،میشه ترتیب نوشتن صحیح رو بهم بگید
من اینطوری نوشتم :
کد:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication2
{
class Program
{
public void H1()
{
sem.WaitOne();
Console.WriteLine("H1 is produce");
sem.Release();
}
public void H2()
{
sem.WaitOne();
Console.WriteLine("H2 is produced");
sem.Release();
}
public void O()
{
sem.WaitOne();
Console.WriteLine("O is produced");
sem.Release();
}
public void Water()
{
Console.WriteLine("H2O ");
}
static void Main(string[] args)
{
Semaphore sem = new Semaphore(1, 3);
Thread t = new Thread(H1);
t.Start();
}
}
}

می خوام با فراهم شدن 2تا هیدروژن و 1 اکسیژن ، یه مولکول آب تولید شه و کار توابع تموم شه.
چه جوری 3تا تابع همزمان اجرا شوند؟
تو دستور thread t=new thread(my thread) وقتی تو پرانتز اسم تابع ،مثلا H2 رو مینویسم error میده ،چه کنم؟
چه ه جوری به سیستم بگم که وقتی مولکول ها تولید شدند ،آب را بسز و کار رو تموم کن؟
ممنون میشم اگه هر قسمتش رو که بلد بودید بهم بگید.

mosi_asgari
جمعه 04 دی 1388, 23:18 عصر
سلام

علت اینکه کد شما خطا میده به خاطر 2 دلیل زیره:

1- از یک متد استاتیک نمی شه به متدهای غیر استاتیک دسترسی داشت.شما از متد Main که یک متد استاتیک است می خواهید متد های غیر استاتیک H1 و h2 و O رو صدا بزنید خوب اشتباه است. برای حل این موضوع H1,h2و O رو هم استاتیک کن.

2- تعریف متغیر sem ( متغیر Semaphor ) در متد Main به صورت Local تعریف شده.خوب نمی شه از متغیر sem در H1 و H2 و O استفاده کرد.

zo_se1386
سه شنبه 08 دی 1388, 10:49 صبح
سلام بازم ممنونمیشه بگید که این سمافور رو کجای برنامه باید بنویسم ؟هر جارو امتحان میکنم error میده؟برای اجرای همزمان متدها چه دستوری داریم؟ thread.start();که فقط انگار یه متد رو میگیره!