الدرس الثالث: Semaphore

سلسلة من الدروس في الـ POSIX

الدرس الثالث: Semaphore

Semaphore:

أسلوب حماية للمناطق الحرجة و المصادر المشتركة بين الـ Threads في أنظمة التشغيل، يعتمد على وجود عدّاد و رتل انتظار. يختبر الـ Thread قيمة العداد إن كانت أكبر تماماً من الصفر يقوم بإنقاصها و دخول المنطقة الحرجة ، بعد الخروج من المنطقة الحرجة – الانتهاء من استخدام المصدر المشتركيقوم بزياد قيمة العداد. إن كانت قيمة العداد صفر يدخل الـ Thread في رتل الانتظار حتى تتم زيادة قيمة العداد من قبل Thread أخرى الذي فيحرير أول Thread في رتل الانتظار أي ان هذا الرتل هو FIFO.

تستخدم الـ semaphore في حال تعدّد المصادر، تتم تهيئة العدّاد بقيمة مساوية لعدد المصادر المتوفرة و هنا يتم التمييز بين نوعين الأول هو Binary Semaphore و الذي تكون فيه قيمة العداد مساوية لـ 1 و تعتبر مماثلة لعمل متحولات الإقصاء المتبادل mutex. النوع الثاني هو Counting Semaphore تكون قيمة العداد > 1 و التي تسمح بتنظيم الوصول لمصدر مشترك متعدد النسخ.

POSIX Semaphore:

توفر POSIX نوع بيانات و مجموعة من التوابع تسمح بإنشاء semaphores و قيادتها من خلال تضمين المكتبة semaphore.h. يوجد نوعين من الـ semaphores في POSIX:

1-Unnamed Semaphore:تنظم الوصول للمصادر المشتركة بين مجموعة الـ Threads المرتبطة بـ Process واحدة – المشتركة بنفس الأب. لاستخدامها نعرف متحول من نوع sem_t، يجب تهيئة الـ semaphore بقيمة العداد

  • sem_init(sem_t *sem, int pshared, unsigned int value );

إن كانت قيمة pshreadأكبر من الصفر فهذا يعني أنه يمكن استخدام الـ semaphore من أكثر من Processes. تمثل value عدد المصادر المشتركة ولا تكون قيمة سالبة.

نتحكم بالولوج للمنطقة الحرجة – الحصول على المصادر المشتركةمن خلال التابعين:

  • sem_wait(sem_t *sem);

يقوم التابع بفحص العداد و يدخل المنطقة الحرجة إن كانت قيمة العداد > 0 و ينقص قيمة العداد بمقدار 1، و إلا يدخل الـ Thread في حالة wait حتى تتم زيادة قيمة العداد من قبل Thread آخر.

  • sem_post(sem_t *sem);

يقوم التابع بزيادة قيمة العداد مما يسمح لـ Thread آخر في رتل الانتظار بالحصول على المصدر المشترك – الولوج للمنطقة الحرجة.

مثال: إعادة حل مسألة المشفى باستخدام الـ Semaphores.

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<semaphore.h>

#define Number_of_Patient 10

int Doctor = 2, Nurse = 6 , Clerk = 1 , Bed = 6 ;

sem_t sem_doc,sem_nur,sem_cle,sem_bed;

/* Simulates the Check In step of the simulation */

void check_in(int id)

{

sem_wait(&sem_cle);

sleep(4);

printf(“check_in %i\n”,id);

sem_post(&sem_cle);

}

/* Simulates the Assess step of the simulation */

void assess(int id)

{

sem_wait(&sem_nur);

sem_wait(&sem_bed);

sleep(6);

printf(“assess %i\n”,id);

sem_post(&sem_nur);

}

/* Simulates the Treat step of the simulation */

void treat(int id)

{

sem_wait(&sem_doc);

sleep(10);

printf(“treat %i\n”,id);

sem_post(&sem_doc);

}

/* Simulates the Reassess step of the simulation */

void reassess(int id)

{

sem_wait(&sem_nur);

sleep(5);

printf(“reassess %i\n”,id);

sem_post(&sem_nur);

sem_post(&sem_bed);

}

/* Simulates the Check Out step of the simulation */

void check_out(int id)

{

sem_wait(&sem_cle);

sleep(2);

//time(&t_check_out);

printf(“check_out %i\n”,id);

sem_post(&sem_cle);

}

/* Simulates the arrival of a patient in the ER, and the different steps that the patient goes through.

*/

void *arrive(void *n)

{

int id = *(int *)n;

printf(“hello %i\n”,id);

check_in(id);

assess(id);

treat(id);

reassess(id);

check_out(id);

printf(“good bye %i!\n”,id);

}

int main(int argc,char *argv[])

{

//Start the simulation with one patient (id = 0)

int rc,i ;

pthread_t threads[Number_of_Patient];

int threads_id[Number_of_Patient];

sem_init(&sem_doc,0,Doctor);

sem_init(&sem_nur,0,Nurse);

sem_init(&sem_cle,0,Clerk);

sem_init(&sem_bed,0,Bed);

for(i=0 ; i< Number_of_Patient ; i++)

{

threads_id[i]=i;

rc = pthread_create(&threads[i], NULL, arrive, (void *) &threads_id[i]);

}

for(i=0 ; i< Number_of_Patient ; i++)

rc = pthread_join(threads[i], NULL);

return 0;

}

ملاحظة: أعد النظر في الحل السابق لاكتشاف إمكانية حصول Deadlock و قدم حلاً لذلك!

2- Named Semaphore:تنظم الوصول للمصادر المشتركة بين مجموعة من الـ Processes –حتى الغير مشتركة بنفس الأب، تعتمد على إنشاء ملف افتراضي تربط به الـsemaphore ثم تتم عملية التحكم بذات الأسلوب في unnamed semaphore.

يتم إنشاء named semaphore و تهيئتها بمجموعة من التوابع:

  • sem_open();

  1. sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

  2. sem_open(const char *name, int oflag);

يقوم التابع بإنشاء ملف وهمي جديد(1) أو فتح ملف موجود مسبقاً(2).

name: اسم الملف الوهمي الذي سنقوم بإنشاءه – فتحه.عندما نريد من الـ semaphore أن تحمي مصدراً مشتركاً بين Processes غير مشتركة بالأب يجب أن يكون اسم الملف مسبوقاً بـ / .

oflag:تمثل علم دلالة يأخذ القيمة صفر عندما نريد فتح ملف وهمي موجود مسبقاً و تأخذ القيمة O_CREATعندما نريد إنشاء ملف وهمي جديد. عند تمرير O_CREAT|O_EXCLفإن التابع يعيد خطأ عند محاولة إنشاء ملف وهمي باسم مستخدم مسبقاً.

mode:تحديد سماحيات الوصول للملف.

value: قيمة العداد المرتبط بالـsemaphore – عدد المصادر المشتركة.

ملاحظة: يجب تضمين المكتبة fcntl.h لاستخدام O_CREAT , O_EXCL.

  • sem_close(sem_t *sem);

إغلاق الملف الوهمي المرتبط بالـ sem.

  • sem_unlink(char *name);

الانتهاء كلياً من التعامل مع الملف الوهمي، أي تابع sem_close يتم استدعائه من الـ Processes –التي تتنافس على المصادر المشتركة المحمية بالملفبعد التابع sem_unlink سيؤدي إلى حذف الملف الوهمي نهائياً.

مثال1:

P1 code:

#include <stdio.h>

#include <stdlib.h>

#include <semaphore.h>

#include <fcntl.h>

sem_t *named_sem;

int main(int argc, char *argv[])

{

named_sem = sem_open(“/sem”,O_CREAT,0666,1);

printf(“I am P1 and I am wating for the named sem\n”);

sem_wait(named_sem);

printf(“I got the named sem\n”);

sleep(10);

sem_post(named_sem);

printf(“I finished ,Bye!\n”);

sem_unlink(“/sem”);

sem_close(named_sem);

}

P2 code:

#include <stdio.h>

#include <stdlib.h>

#include <semaphore.h>

sem_t *named_sem;

int main(int argc, char *argv[])

{

named_sem = sem_open(“/sem”,0);

printf(“I am P2 and I am wating for the named sem\n”);

sem_wait(named_sem);

printf(“I got the named sem\n”);

sleep(5);

sem_post(named_sem);

printf(“I finished ,Bye!\n”);

sem_unlink(“/sem”);

sem_close(named_sem);

}

مثال 2:

#include <stdio.h>

#include <semaphore.h>

#include <fcntl.h>

sem_t * sem;

int pid;

void func()

{

sem_wait(sem);

if(pid==0)printf(“Child entered\n”);

else if(pid>0)printf(“Parent entered\n”);

sleep(2);

sem_post(sem);

if(pid==0) printf(“Child exited\n”);

else if(pid>0) printf(“Parent exited\n”);

sem_unlink(“sem”);

sem_close(sem);

}

int main()

{

sem = sem_open(“sem”,O_CREAT,0666,1);

pid=fork();

if(pid==0)

{

printf(“In child\n”);

func();

}

else

{

func();

}

}

ملاحظة: يمكن استخدام unamed semaphore في إدارة ولوج عدة Processes كما في named semaphore وذلك بوضع pshared =1، لكن يتطلب ذلك تضمين هذه الـ semaphore في ذاكرة مشتركة يدوياً.

مثال للإطلاع:

#include <semaphore.h>

#include <stdio.h>

#include <sys/mman.h>

sem_t * sem;

int pid;

void func()

{

sem_wait(sem);

if(pid==0)printf(“Child entered\n”);

else if(pid>0)printf(“Parent entered\n”);

sleep(2);

sem_post(sem);

if(pid==0) printf(“Child exited\n”);

else if(pid>0) printf(“Parent exited\n”);

}

int main()

{

/* Put semaphore in shared memory */

sem = mmap(0, sizeof(sem_t), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

sem_init(sem,1,1);

pid=fork();

if(pid==0)

{

printf(“In child\n”);

func();

About زين العابدين

مهندس حواسيب - معهد IDA - جامعة Braunshweig التقنية.
هذا المنشور نشر في دروس تعليمية وكلماته الدلالية , , , , , , , , . حفظ الرابط الثابت.

7 ردود على الدرس الثالث: Semaphore

  1. يقول hi:

    مادة غلسه جداااااااااااااااااا
    للاسف اقرا الشرح وكأنه طلاسم المادة الوحيدة في تخصصي احفظها حفظ بدون فهم
    شكرا جزيلا على شرحك واجتهادك

  2. يقول F:

    حلو جزاك الله الف خير
    :)

    من ناحية الماده حلوه في حال وجود من يشرح شرح ممتاز
    لكن ربك يعين

  3. يقول jawares:

    nice description
    i am studying this course now in USA
    you did like what my professor did
    thanks

  4. يقول nn:

    لم افهم

  5. شرح جميل جزاك الله خير
    بجد فهمت اشياء كثير كانت صعبة عليا
    شكراً جزيلاً : )

  6. يقول Tagreed:

    السلام عليكم… أستاذ زين لدي أسئلة حول السيمفور و هذه الموضوع لم يغطي أسئلتي ويبلور فكرتها عندي فإذا ممكن أن ترسل لي إيميلك حتى أفهمك ما أريده بالضبظ وإذا كان عندك المعلومات ؟؟

أضف تعليقاً

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s