آموزش برنامه نویسی Multi-threading در C++ به وسیله SDL
آموزش برنامه نویسی Multi-threading در C++ به وسیله SDL
(قسمت اول)
((((مواظب باشید که تو برنامه ها جای کرکتر اول و آخر را عوض کنید))))
احتمالا چیزهایی در مورد برنامه ها Multi-threaded شنیده اید یا اسم فناوری جدید Intel به اسم Hyper-Threading را شنیده اید که اگر این فناوریبر روی CPU فعال باشد CPU جوری رفتار می کند که سیستم عامل فرض کند به جاییک CPU 4 عدد CPU در سیستم موجود است که در ان موقع اگر سیستم عامل رویاین قسمت کار کرده باشد می تواند به خوبی از این خاصیت استفاده کند و مثلااجرا برنامه ها را بین 4 CPU تقسیم کند که سرعت به طرز قابل توجهی بالا میرود فعلا که دارم این مقاله را می نویسم بین سیستم عامل هایی که برای PCموجود است Linux Fedora Core بین سیستم عامل های دیگر می تواند به بهتریننحو از چند CPU در ان واحد استفاده کند که می تواند تا حدود 60-70 % ازاین قابلیت استفاده کند.و البته ویندوز هم به مقدار قابل توجهی از اینخاصیت پشتیبانی می کند

و در حال حاضر این خاصیت SDL در سیستم عامل MacOS X کار گذاشته نشده استبه خاطر این که اساسا PCهای Macintosh تک CPU هستند و نیازی به همچین کاریاحساس نمی شد.



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



Thread در برنامه نویسی به پروسه ای می گویند که بخشی از یک پروسه بزرگتر یا یک برنامه باشد.



همانطور که گفتم برنامه نویسی Multi-threading به شما قدرت فوق العاده ایبرای اجرای چند کار در یک زمان را می دهد(البته بر روی سیستم های تک CPUاین یک بحث تئوری است ولی فوق العاده به درد به خور حتی در ساخت بازی) دراستفاده از thread ها باید نهایت دقت را بخرج دهید.



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



خوب اول ببینیم چه گونه می توانیم یک thread ایجاد کنیم.

SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data);

این تابع دو پادامتر دریافت می کند یک اشاره گر به تابع و داده ای که بایدتابع بپذیرد و نوع برگشتی ان هم از نوع اشاره گر به SDL_Thread است.

تابع شما شکلی مانند شکل زیر دارد

int ThreadFunction(void* data);

که این تابع یک پارامتر برای پردازش دریافت می کند و یک مقدار int برمیگرداند وقتی thread مرد این مقدار بر گشت داده می شود.

اگر به هر طریقی بخواهید یک Thread را متوقف کنید می توانید از تابعSDL_KillThread استفاده کنید یک مقدار خشن به نظر می رسد ولی تا حالا کسیپیدا نشده که از حقوق thread ها دفاع کند!!!

void SDL_KillThread(SDL_Thread *thread);

اگر می خواهید یک مقدار با حوصله تر یک thread را متوقف کنید می توانید از SDL_WaitThread استفاده کنید.

void SDL_WaitThread(SDL_Thread *thread, int *status);

این تابع یک thread را دریافت کرده و سپس یک اشاره گربه یک عدد صحیح میگیرد و منتظر اتمام کار thread می شود و مقدار برگشتی را در status قرارمی دهد اگر به مقدار برگشتی اهمیتی نمی دهید می توانید مقدار NULL را بهعنوان پارامتر دوم بفرستید.



هر thread یک ID 32 بیتی مخصوص خود است که برای مدیریت thread ها می تونیدازش استفاده کنید و به وسیله فراخوانی تابع SDL_ThreadID درون thread میتوانید مقدار ان را بیابید.

Uint32 SDL_ThreadID(void);

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

Uint32 SDL_GetThreadID(SDL_Thread *thread);



نکته : برای استفاده از thread ها حتما باید فایل SDL_Thread.h رابارگزاری نمایید و در thread ها نیازی به استفاده از SDL_Init نیز وجودندارد.



MUTEX:

موتکس راه ساده ای برای بر قرار کردن ارتباط بین Thread ها است و یکی ازاین دو حالت رو به خودش می گیرد Locked و Unlocked . وقتی یک موتکس بهوسیله یک thread قفل می شود و thread دیگری خواهان قفل کردن Mutex می شودباید منتظر بماند تا thread قبلی ان را از حالت قفل بیرون بیاورد.

شما به راحتی می توانید بوسیله تابعSDL_CreateMutex یک Mutex بسازید.

SDL_mutex *SDL_CreateMutex(void);

این تابع هیچ پارامتری نمی گیرد و یک اشاره گر به SDL_mutex بر می گرداند.

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

void SDL_DestroyMutex(SDL_mutex *mutex);



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

int SDL_mutexP(SDL_mutex *mutex);

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

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

int SDL_mutexV(SDL_mutex *mutex);

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

یک نمونه ساده ولی جالب از استفاده از Mutex :



g_pMutex=SDL_CreateMutex();

SDL_LockMutex(g_pMutex);

g_pThread=SDL_CreateThread(ThreadFunction,NULL);

SDL_UnlockMutex(g_pMutex);

SDL_WaitThread(g_pThread,NULL);

در اینجا ما در ابتدا یک موتکس می سازیم سپس ان را قفل می کنیم سپس یکthread می سازیم و بعد از ان mutex را از حالت قفل بیرون می اوریم و منتظرتوقف thread می شویم.

تابع thread مان هم به شرح زیر است.

int ThreadFunction(void* data)

{

fprintf(stdout,”Thread %d: Initialized! ”,SDL_ThreadID());

fprintf(stdout,”Thread %d: Attempting to lock mutex. ”,SDL_ThreadID());

SDL_LockMutex(g_pMutex);

fprintf(stdout,”Thread %d: Mutex is locked. ”,SDL_ThreadID());

fprintf(stdout,”Thread %d: Unlocking mutex. ”,SDL_ThreadID());

SDL_UnlockMutex(g_pMutex);

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

return(0);

}

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