Transcript Mutex
برنامه نويسي چند نخي با POSIX
استاد :دکتر پارسا
ارائه دهنده :مهدي سخائي نيا
نيمسال دوم 88-89
فهرست مطالب
مفاهيم اوليه نخها
برنامه نويسي چند نخي
مدلهاي پياده سازي نخها
انواع مدلهاي نخ کشي
ايجاد و خاتمه نخ در POSIX
قابليت الحاق
ارتباط بين نخها و همگام سازي
2
نخ ()thread
نخ يک جريان اجرايي در فرآيند( )processمي باشد که
مي -تواند بصورت مستقل ،توسط هسته زمانبندي گردد
و از فضاي آدرسي يکسان باساير نخها به اشتراک
استفاده نمايد.
3
مستقل بودن
چون نخها بصورت مستقل زمانبندي مي شوند ،نخها
بصورت همروند با ساير نخها اجرا مي شوند و امکان
اجراي موازي در سيستمهاي چند پردازنده اي وجود
دارد .اين بدين معناست که هر نخ بايد منابع مربوط به
خودش داشته باشد:
شمارنده برنامه
فضاي پشته
مجموعه ثبات ( فضايي براي ذخيره کردن مقدار ثباتها
زماني که پردازنده در اختيار ندارد)
زمانبندي پردازنده )
اولويت(بهره گيري از 4
همروندي()concurrency
عمليات همروند هستند اگر امکان اجراي نوبتي آنها فراهم گردد
بنحويکه اجراي هر عمليات بصورت مستقل پيشرفت داشته
باشد.
نخها مي توانند براي استفاده از پردازنده با هر ترتيبي و با هر نخ
ديگر زمانبندي شوند .ممکن است پردازنده از يک نخ در هر نقطه از
اجرايش گرفته شده و با نخ ديگري جايگزين شود.
عمليات که سبب توقف اجراي يک نخ شده ،سبب توقف اجراي ساير
نخ ها نمي شود.
اگر ترتيب اجراي يک نخ مهم باشد يا يک نخ بايد قبل از اجراي نخ
ديگري کارش به پايان برسد ،بنابراين اجراي نخ بايد براي هماهنگي
عمليات همگام گردد.
5
مزاياي برنامه نويسي چند نخي
بهره گيري از اجراي موازي بر روي معماري چند
پردازنده -اي براي اجراي سريعتر.
افزايش کارايي روي معماري تک پردازنده اي بوسيله
فراهم آوردن امکان اجراي يک فرآيند بهنگام عمليات
ُکند ورودي-خروجي يا بالک شدن عملياتهاي ديگر.
پاسخدهي سريعتر در سيستمهاي بي درنگ و محاوره
اي که بايد به رخدادهاي ناهمگام پاسخ دهند.
6
مشکالت برنامه نويسي چند نخي
سربار محاسباتي حاصل از همگام سازي و زمانبندي
در برنامه ها با امکان توازي سازي کم ممکن است قابل
تحمل نباشد.
نياز به دقت و نظم برنامه نويسي بيشتر براي طراحي و
هماهنگي ترتيبهاي اجراي مختلف.
اشکال زدايي مشکلتر.
7
POSIX
"Portable Operating System Interface [for Unix]"
POSIX
standard
for
thread
programming
interface(1995)
Implementations of POSIX standard are referred to
as POSIX threads or Pthreads.
Latest Edition IEEE std 1003.1,2004
Available for Linux and Unix OS family
Availabe for Windows
As Open Source http://sourceware.org/pthread-win32
8
پياده سازي نخ
پياده سازي نخ در POSIXدر سه اليه انتزاعي
9
اليه هاي انتزاعي
Pthreadتوصيف POSIXبراي رفتار نخها است که برنامه
نويس سيستم مستقيما از آن استفاده مي کند.
نخ سطح کرنل عنصري است که توسط کرنل ،بعنوان متن
اجراي يک نخ در فرآيند ،بطور واقعي ايجاد ،زمانبندي و
مديريت مي شود .چگونگي مديريت نخ وابسته به سيستم عامل
است.
کتابخانه يک روال پوششي است که فراخوان کرنل سيستم را
پياده سازي مي کند .بعضا امکاناتي براي ايجاد ،زمانبندي و
مديريت نخها مستقل از هسته فراهم مي شود که عنصر ايجاد
سطح کاربر ناميده مي شود.
شده توسط کتابخانه ،نخ
10
سه مدل پياده سازي نخها
چند به يک
يک به يک
چند به چند
11
چند به يک
Pthreadبعنوان نخ سطح کاربر پياده سازي مي شود.
کتابخانه زمان اجرا نيز در حالت کاربر قرار دارد و نخ را زمانبندي
مي کند
براي سيستم عامل قابل مشاهده نيستند.
هر فرايند به يک نخ سطح کرنل نگاشت مي شود.
مشخصات
قابليت حمل بيشتر بدليل عدم نياز به پشتيباني کرنل
تعويض متن سريعتر بين نخها
عدم استفاده از مزيت معماري چند پردازنده اي
Mach C-threads, BSD, Solaris UI-threads,DCE-threads
12
چند به يک
13
يک به يک
Pthreadsبعنوان نخ سطح هسته در داخل هسته پياده سازي مي شود.
کتابخانه براي هر نخ سطح کاربر يک نخ سطح کرنل تقاضا مي کند
کتابخانه نخ ممکن است هنوز بطور گسترده با همگام سازي نخها درگير باشد اما
کرنل ايجاد و زمانبندي نخ را انجام مي دهد
تعداد نخها براي هر فرآيند بايد معلوم باشد.
مشخصات
معموال در تعويض متن نخها ُکند مي باشد چون نياز به مداخله کرنل دارد .اين بدين
معني است که برنامه ها که مکررا نياز دارند تا براي همگام سازي بالک شوند
کندتر از ديگر مدلها اجرا خواهند شد
در يک فرايند از امکانات معماري چند پردازنده اي بطور کامل استفاده مي گردد
Windows,Linux
14
يک به يک
15
چند به چند
سعي به ادغام مزيت مدلهاي يک به يک و چند به يک دارد.
نياز گسترده به هماهنگي بين کتابخانه نخ سطح کاربر و سطح کرنل دارد .آنها در مسئوليت
زمانبندي شريک هستند
هر فرايند داراي مخزنی از نخهاي سطح کاربر است.
نخهاي سطح کاربر توسط کتابخانه سطح کاربر مديريت شده و آماده اجرا مي گردند.
کرنل يکي از نخهاي سطح کاربر را انتخاب کرده و به يکي از نخهاي سطح کرنل متعلق به
مجموعه نخهاي فرآيند نگاشت مي کند.
مشخصات
بيش از يک نخ سطح کاربر مي تواند به يک نخ سطح کرنل نگاشت شود.
در يک فرايند از امکانات معماري چند پردازنده اي بطور کامل استفاده مي گردد
بيشتر تعويض متن در حالت کاربر است ،تعويض نخ هاي کاربر بدون تعويض نخهاي سطح
کرنل صورت مي گيرد
پيچيدگي زياد براي هماهنگ کردن کتابخانه سطح کاربر و هسته
Solaris, HP, AIX
16
چند به چند
17
انواع مدل هاي نخ کشي
Boss-worker
Peer-to-peer
pipeline
18
انواع مدل هاي نخ کشي
Boss-worker
يک نخ( )bossساير نخها( )workerرا ايجاد نموده و به
هر کدام وظيفه اي را تخصيص مي دهد.
نخ workerوظيفه را اجرا نموده و در صورت نياز با
ساير نخها همگام مي شود.
نخ bossدر يک حلقه مداوما رخدادها را دريافت کرده و
نخهايي براي اجراي وظايف ايجاد مي نمايد.
نخ bossمي تواند منتظر اجرا و خاتمه يک نخ بماند.
19
انواع مدل هاي نخ کشي
Peer-to-peer
همه نخهاي وضعيت کاري يکسان دارند
يک نخ وظيفه ايجاد ساير نخها را دارد ولي خودش هم
workerمحسوب مي شود.
Pipeline
مانند خط مونتاژ:پردازش دنباله اي از اقالم در مراحل
مختلف.
براي هر مرحله يک نخ ورودي را دريافت کرده و آنرا
پردازش مي نمايد .سپس نخ ديگر براي مرحله بعد پردازش
ديگري را روي ورودي20انجام مي دهد.
مدل نخ کشي Pthread
نخ ها در يک فرآيند وجود دارند.
همه نخ ها ”همتا“( )peerهستند:
مدل پدر-فرزند صريح نمي باشد
استثنا “main thread” :اطالعات فرآيند را نگه داري مي کند
Pthread API
مديريت نخ هاcreating, detaching, joining,etc :
:Mutexمربوط به همگام سازي مي باشد.
متغيرهاي شرطي :ارتباط بين نخهايي که از mutexاشتراکي استفاده
مي کنند
21
main thread
نخ اوليه زماني ايجاد مي شود که تابع
بوسيله بارکننده فرآيند احضار گردد.
اگر main threadخاتمه يابد ،فرايند خاتمه مي يابد حتي
اگر نخ هايي در حال اجرا وجود داشته باشد ،مگر
اقدامات احتياطي در نظر گرفته شده باشد.
)(main
براي اجتناب از خاتمه کامل نخ ،از
مي گردد.
22
)(pthread_exit
در
C
استفاده
ايجاد نخ
pthread_create(
pthread_t *tid,
const pthread_attr_t *attr,
void *(*func)(void *),
void *arg);
tid - pointer to the identifier of the created thread
attr - thread attributes
func - pointer to the function the thread will execute
arg - the argument of the executed function (usually a struct)
23
ايجاد نخ
;)pthread_create(tid, attr, func, arg
زمانيکه تابع )( funcخاتمه يابد( )returnنخ هم به پايان مي
رسد.
مقدار بازگشتي pthread_createاگر صفر باشد يعني
اجرا موفق بوده و در صورتيکه ناموفق باشد عدد مثبتي به
عنوان شماره خطا بازگشت داده مي شود.
متغير errnoمقدار دهي نمي گردد.
شناسه( )IDنخ در tidبازگشت داده مي شود.
24
ايجاد نخ
;)pthread_create(tid, attr, func, arg
خصيصه نخ که با attrمي توان مقداردهي کرد:
detached state
scheduling policy
در صورتيکه attrبرابر NULLقرار دهيم ،خصيصه
پيش فرض سيستم را به نخ خواهد داد.
25
پايان نخ
خاتمه روال اصلي براي ايجاد نخها
فراخواني زير روال pthread_exitدر نخ
خاتمه يک نخ توسط نخ ديگر با روال pthread_cancel
خاتمه فرآيند توسط روالهايي مانند exit
26
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS
5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
27
ارسال پارامتر به نخ
امکان ارسال فقط يک پارامتر به نخ فراهم شده است
براي ارسال بيش از يک مقدار از structاستفاده مي شود
همه پارامترها بايد تبديل نوع به )* (voidگردند
28
مثال – ارسال پارامتر به نخ
long *taskids[NUM_THREADS];
for(t=0; t<NUM_THREADS; t++)
{
taskids[t] = (long *) malloc(sizeof(long));
*taskids[t] = t;
printf("Creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);
...
}
int rc;
long t;
for(t=0; t<NUM_THREADS; t++)
{
printf("Creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *) &t);
...
}
29
الحاق()joining
الحاق يکي از راههاي همگام کردن ()synchronization
دو نخ مي باشد
روال )( pthread_joinروال فراخواننده خود را مسدود
مي نمايد تا زمانيکه نخ مشخص شده( )thraedidخاتمه
يابد
30
الحاق()joining
اطالع از وضعيت نخ خاتمه يافته()status
بايد نخ با )( pthread_exitخاتمه يافته باشد.
امکان الحاق چند نخ به يک نخ بطور همزمان وجود
ندارد.
دو روش همگام سازي ديگر:
Mutex , Condition Variable
31
قابليت الحاق
زمانيکه يک نخ ايجاد مي شود ،با مقداردهي يکي از خصايصش مي توان قابليت الحاق
نخ را تعريف کرد:
Joinable or detached
قابل الحاق
منفصل
بطور پيش فرض نخها قابل الحاق شدن هستند
منابع تا زمانيکه الحاق رخ دهد حفظ مي شود
نمي توانند به نخي ملحق شوند
منابع در زمان خاتمه نخ آزاد مي شوند
عملکرد
تعريف يک متغير از نوع داده pthread_attr_t
مقداردهي اوليه و پيش فرض متغير خصيصه با روال )(pathread_attr_init
مقدار دهي خصيصه با )(pathrad_attr_setdetachstate
آزادسازي منابع استفاده شده توسط خصيصهpthread_attr_destroy() :
32
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 4
void *BusyWork(void *t)
{
int i;
long tid;
double result=0.0;
tid = (long)t;
printf("Thread %ld starting...\n",tid);
for (i=0; i<1000000; i++)
{
result = result + sin(i) * tan(i);
}
printf("Thread %ld done. Result = %e\n",tid, result);
pthread_exit((void*) t);
}
33
int main (int argc, char *argv[])
{
pthread_t thread[NUM_THREADS];
pthread_attr_t attr;
int rc;
long t;
void *status;
/* Initialize and set thread attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(t=0; t<NUM_THREADS; t++) {
printf("Main: creating thread %ld\n", t);
rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Free attribute and wait for the other threads */
pthread_attr_destroy(&attr);
for(t=0; t<NUM_THREADS; t++) {
rc = pthread_join(thread[t], &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status
of %ld\n",t,(long)status);
}
printf("Main: program completed. Exiting.\n");
pthread_exit(NULL);
}
34
ارتباط بين نخها
متغيرهاي سراسري
پارامترهاي ارسالي به نخ بهنگام ايجاد نخ
فايلها
مشکل :دسترسي همزمان به منابع
35
ارتباط بين نخها
36
روشهاي همگام سازي
همگام سازي
ارتباط بين نخها از طريق به اشتراک گذاشتن منابع سخت
افزاري و نرم افزاري ممکن است که براي دسترسي به آنها
نياز به همگام سازي وجود دارد.
مکانيزم هاي همگام سازي
سمافور و mutex
قفلهاي خواندن-نوشتن
متغيرهاي شرطي
37
Mutex
منبع اشتراکي :داده
با استفاده از متغيرهاي سراسري يا فايلها
مشکل :شرايط رقابتي در دسترسي به ناحيه حافظه
ناحيه بحراني :قطعه اي از کد که روي ناحيه مشترک تغييرات
ايجاد مي نمايد
راه حل :انحصار متقابل در ناحيه بحراني
:mutexسمافور دودويي براي جلوگيري از شرايط
رقابتي در ناحيه بحراني
38
Mutex
توالي عمليات نمونه براي استفاده از mutex
ايجاد و مقدار دهي اوليه mutex
تالش چند نخ براي قفل کردن mutex
موفق شدن فقط يک نخ و در اختيار گرفتن mutex
اجراي تعدادي دستور توسط نخي که mutexرا در اختيار
دارد
باز کردن قفل توسط نخي که mutexرا در اختيار دارد
ساير نخها mutexرا در اختيار گرفته و تکرار مراحل
فوق
آزادسازي mutex
39
Mutex
تعريف و مقداردهي اوليه mutex
تعريف متغير از نوع pthread_mutex_t
مقداردهي اوليه
ايستا در زمان تعريف
;pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER
پويا ,با استفاده از روال )(pthread_mutex_init
با استفاده از شيء خصيصه مي توان خصوصيات شيء mutexرا نيز
تعريف نمود.
40
Mutex
آزاد سازي اشيا
با استفاده از روالmutex آزاد سازي شيء
pthread_mutex_destroy()
mutex آزاد سازي شيء خصيصه
pthread_mutexattr_destroy()
41
Mutex
قفل گذاري mutex
قفل با روال :
در صورتيکه mutexقبال توسط نخي قفل شده باشد ،نخ فراخواننده روال
بالک مي شود تا زمانيکه قفل mutexآزاد گردد.
قفل با روال :
)(pthread_mutex_lock
)(pthread_mutex_trylock
در صورتيکه mutexقبال توسط نخي قفل شده باشد ،روال خاتمه سافته و
خطايي مبني بر busyبر مي گرداند(مناسب براي جلوگيري از .)deadlock
بازکردن قفل mutex
فراخواني روال
کننده mutex
)( pthread_mutex_unlockتوسط نخ قفل
42
typedef struct{
double
*a;
double
*b;
double
sum;
int
veclen;
}DOTDATA;
#define NUMTHRDS 4
#define VECLEN 100
DOTDATA dotstr;
pthread_t callThd[NUMTHRDS];
pthread_mutex_t mutexsum;
void *dotprod(void *arg)
{
int i, start, end, len ;
long offset;
double mysum, *x, *y;
offset = (long)arg;
len = dotstr.veclen;
start = offset*len;
end
= start + len;
x = dotstr.a;
y = dotstr.b;
mysum = 0;
for (i=start; i<end ; i++) {
mysum += (x[i] * y[i]);
}
pthread_mutex_lock (&mutexsum);
dotstr.sum += mysum;
pthread_mutex_unlock (&mutexsum);
pthread_exit((void*) 0);
}
43
int main (int argc, char *argv[])
{
long i;
double *a, *b;
void *status;
pthread_attr_t attr;
a = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
b = (double*) malloc (NUMTHRDS*VECLEN*sizeof(double));
for (i=0; i<VECLEN*NUMTHRDS; i++){
a[i]=1.0;
b[i]=a[i];
}
dotstr.veclen = VECLEN;
dotstr.a = a;
dotstr.b = b;
dotstr.sum =0;
pthread_mutex_init(&mutexsum, NULL);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(i=0; i<NUMTHRDS; i++){
pthread_create(&callThd[i], &attr, dotprod, (void *)i);
}
pthread_attr_destroy(&attr);
for(i=0; i<NUMTHRDS; i++)
pthread_join(callThd[i], &status);
printf ("Sum = %f \n", dotstr.sum);
free (a);
free (b);
pthread_mutex_destroy(&mutexsum);
pthread_exit(NULL);
}
44
قفلهاي خواندن -نوشتن
ورود چند نخ به ناحيه بحراني
در صورتيکه فقط عمل خواندن توسط نخها صورت پذيرد
در صورتيکه يک نخ عمل نوشتن را انجام دهد ساير نخها
نمي توانند وارد ناحيه بحراني گردند.
45
متغيرهاي شرطي
امکان همگام سازي بر اساس مقادير داده
mutexبر اساس دسترسي به داده همگام سازي مي نمود
Polling
متغيرهاي شرطي هميشه با يک mutexبکار مي
روند
46
متغيرهاي شرطي
مراحل کار
تعريف و مقداردهي اوليه متغيرهاي سراسري :در نخ اصلي
تعريف و مقدار دهي شيء متغيرهاي شرطي :در نخ اصلي
تعريف و مقداردهي متغير : mutexدر نخ اصلي
ايجاد دو نخ Aو B
نخ A
انجام کار تا حصول شرايط(رسيدن مقدار يک متغير
به مقدار مشخصي)
قفل کردن mutexو چک کردن متغير سراسري
فراخواني pthread_cond_waitبراي بالک شدن
و انتظار يک سيگنال از نخ ( Bبطور خودکار و
اتميک mutexباز شده ودر اختيار نخ Bقرار مي
گيرد(
وقتي سيگنال دريافت شد mutex ،بطور خودکار و
اتميک قفل مي شود.
باز کردن mutexبصورت صريح
ادامه
47
نخ B
قفل کردن mutex
تغيير متغير سراسري که نخ Aمنتظر آن مي
باشد
چک کردن مقدار متغير سراسري انتظار نخ
Aو بمحض حصول شرايط ايجاد سيگنال به
نخ A
باز کردن mutex
ادامه
فضاي آدرسي نخ
هر داده اي که آدرسش توسط يک نخ تعيين مي گردد،
در فرآيند براي همه نخها قابل دسترسي هست.
شامل متغيرهاي ايستا ،متغيرهاي خودکار و حافظه هاي
تخصيصي با malloc
اين بدين معنا نيست که هر نخ نمي تواند داده اختصاصي
داشته باشد.
48