درس 14 : آموزش برنامه نویسی Multi-threading در C++ به وسیله SDL

قسمت دوم

 

 Semaphore:

 

سمافر در لغت به معنی با پرچم به هم علامت دادن است و کار ان شبیه کار موتکس است با این فرق که بیشتر از دو مقدار locked و unlocked می تواند به خود بگیرد.و سمافر ها حاوی یک مقدار عددی هستند که بسته به شرایط می تواند مقادیر مثبت منفی و صفر به خود بگیرد و تصمیم می گیرد thread ها منتظر بمانند یا کارشان را انجام دهند.سمافرها راه بهتری را برای برنامه ریزی thread ها در اختیار ما می گذارند.

البته برای برنامه های ساده Multi-threading موتکس ها کافی به نظر می رسند.

 

برخلاف موتکس که دارای دو مقدارمیباشد یک سمافر در SDL دارای 2 به توان 32 حالت می باشد تمام مقادیری که یک Uint32 می تواند به خود بگیرد و وقتی مقدار ان صفر است

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

 

برای ساخت semaphore می توانید از تابع SDL_CreateSemaphore استفاده کنید.

SDL_sem *SDL_CreateSemaphore(Uint32 initial_value);

این تابع مقدار اولیه سمافر را دریافت می کند سپس یک اشاره گر به SDL_sem بر می گرداند.

برای نابود کردن یک سمافر هم می توانید از تابع SDL_DestroySemaphore استفاده کنید.

void SDL_DestroySemaphore(SDL_sem *sem);

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

 

سمافرها از Locked و Unlocked استفاده نمی کنند و به جای ان از Wait و Post استفاده می کنند.این دو مثل lock و unlock رفتار می کنند وقتی که در یک سمافر wait کنید اگر مقدار ان بزرگتر از صفر باشد یک واحد از ان کم می شود و سپس thread مورد نظر کار خود را به پایان می رساند.اگر مقدار ان برابر صفر باشد می ایستد تا مقدار ان بزرگتر از صفر شود و سپس اجرا می شود.

وقتی یک سمافر را post می کنید مثل unlock کردن ان می ماند ویکی به مقدار ان اضافه می شود تا thread های دیگر بتوانند کار خود را انجام دهند.

برای wait کردن بر روی سمافر شما باید از تابع SDL_SemWait استفاده کنید.

int SDL_SemWait(SDL_sem *sem);

این تابع صبر می کند تا مقدار سمافر مثبت سود سپس یکی از ان کم می کند و مقدار را بر می گرداند در صورت بروز خطا مقدار 1- را بر می گرداند.

 

همچنین شما می توانید با تایین زمان منتظر یک سمافر باشید

int SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout);

شما می توانید مقدار یک سمافر را با post کردن ان زیاد کنید.

int SDL_SemPost(SDL_sem *sem);

همچنین شما می توانید مقدار یک سمافر را بوسیله تابع SDL_SemValue تشخیص دهید

Uint32 SDL_SemValue(SDL_sem *sem);

که یک سمافر می گیرد و مقدار ان را بر می گرداند.

در زیر مثالی از سمافر امده است توجه کنید متغییر ها قبلا تعریف شده اند :

//create semaphore

g_pSemaphore=SDL_CreateSemaphore(0);

//create three threads

g_pThread[0]=SDL_CreateThread(ThreadFunction,(void*)1);

g_pThread[1]=SDL_CreateThread(ThreadFunction,(void*)2);

g_pThread[2]=SDL_CreateThread(ThreadFunction,(void*)3);

//wait for a second

SDL_Delay(1000);

//post to the semaphore

SDL_SemPost(g_pSemaphore);

در اول کار ما یک سمافر با مقدار اولیه صفر تعریف می کنیم که تا وقتی سمافر post نشود همه thread ها باید منتظر بمانند.سپس 3 thread تعریف می کنیم بعد یک ثانیه صبر می کنیم تا thread ها اماده شوند و سپس سمافر را post می کنیم تا thread ها شروع به کار کنند.

 

وتابع thread ما هم به شکل زیر است.

//thread function

int ThreadFunction(void* data)

{

          //grab thread number

          int threadnumber=(int)data;

          //wait for semaphore

          fprintf(stdout,”Thread %d: Initialized. ”,threadnumber);

          fprintf(stdout,”Thread %d: Waiting for semaphore. ”,threadnumber);

          SDL_SemWait(g_pSemaphore);

          //post to semaphore

          fprintf(stdout,”Thread %d: Done waiting for semaphore. ”,threadnumber);

          fprintf(stdout,”Thread %d: Posting semaphore. ”,threadnumber);

          SDL_SemPost(g_pSemaphore);

          //wait for semaphore again before terminating

          fprintf(stdout,”Thread %d: Waiting for semaphore before terminating.

          ”,threadnumber);

          SDL_SemWait(g_pSemaphore);

          //terminate

          fprintf(stdout,”Thread %d: Terminating. ”,threadnumber);

          SDL_SemPost(g_pSemaphore);

          //return 0

          return(0);

}

هر thread دو بار منتظر سمافر می شود یک بار در شروع thread و یکبار در موقع پایان thread . و نتایج را در فایل stdout.txt می ریزد.(که در اینجا کد مربوط به فایل را در اول کار ننوشتم)

 

1.thread 1 ساخته میشود و منتظر سمافر می شود.

2. thread 2 ساخته میشود و منتظر سمافر می شود.

3. thread3 ساخته میشود و منتظر سمافر می شود.

4.برنامه سمافر را post می کند.

5.ترید 1 از انتظار بیروم می اید و سمافر را post می کند و دوباره منتظر می شود.

6.ترید 2 از انتظار بیروم می اید و سمافر را post می کند و دوباره منتظر می شود.

7.ترید 3 از انتظار بیروم می اید و سمافر را post می کند و دوباره منتظر می شود.

8.سراخر هر 3 ترید بسته می شوند(با جزییاتی که خودتان حدث بزنید).

 

همانطور که می بینید سمافر راه بهتری جلوی روی ما می گذارد و مثلا اگر در برنامه 2 post را می فرستادیم 2 تا thread با هم کار می کردند.

 

 

متغییرهای شرطی :

سر اخر به متغییر های شرطی می رسیم که روشی است برای استفاده درست از موتکس و thread است و بر خلاف موتکس و سمافر دارای حالت (مثل locked یا unlocked) نیست

 

SDL_cond *SDL_CreateCond(void);

بوسیله این تابع می توانیم یک متغییر شرطی تعریف کنیم.

و به وسیله تابع زیر می توانیم یک متغییر شرطی را از بین ببریم.

void SDL_DestroyCond(SDL_cond *cond);

...

به منظور این که سمافر ها تمام نیاز ما را بر طرف می کنند من فعلا متغییر های شرطی را توضیح نمی دهم اگر کسی نیاز به توضیح داشت به من بگویید!

 

نظرات 1 + ارسال نظر
ساسان سه‌شنبه 31 مرداد‌ماه سال 1385 ساعت 12:08 ق.ظ http://opengl.blogfa.com

سلام ایمان جان مطلب خوبی رو شروع کردی. قدیم خیلی در مورد مولتی تریدینگ دنبال مطلب فارسی میگشتم ولی چیزی پیدا نمیکردم. موفق باشی

برای نمایش آواتار خود در این وبلاگ در سایت Gravatar.com ثبت نام کنید. (راهنما)
ایمیل شما بعد از ثبت نمایش داده نخواهد شد