‏إظهار الرسائل ذات التسميات Inter process communication الاتصال بين العمليات. إظهار كافة الرسائل
‏إظهار الرسائل ذات التسميات Inter process communication الاتصال بين العمليات. إظهار كافة الرسائل

Inter Process Communication - الإشارات

 

Inter Process Communication - الإشارات



السؤال الأول الذي يتبادر إلى الذهن هو ، لماذا نحتاج إلى إشارات؟ إجابة بسيطة ، لحماية المنطقة الحرجة / المشتركة المشتركة بين عمليات متعددة.

لنفترض أن العمليات المتعددة تستخدم نفس منطقة الكود وإذا أراد الجميع الوصول إلى المتوازيات ، فإن النتيجة متداخلة. لنفترض ، على سبيل المثال ، أن عدة مستخدمين يستخدمون طابعة واحدة فقط (قسم عام / حرج) ، على سبيل المثال 3 مستخدمين ، مع إعطاء 3 وظائف في نفس الوقت ، إذا بدأت جميع الوظائف بشكل متوازي ، فسيتم تداخل إخراج مستخدم واحد مع آخر. لذلك ، نحتاج إلى حماية ذلك باستخدام الإشارات ، أي قفل القسم الحرج عند تشغيل إحدى العمليات وإلغاء قفلها عند الانتهاء. سوف يتكرر هذا لكل مستخدم / عملية حتى لا تتداخل وظيفة واحدة مع وظيفة أخرى.

بشكل أساسي ، يتم تصنيف الإشارات إلى نوعين -

إشارات ثنائية - حالتان فقط 0 و 1 ، أي مؤمن / غير مؤمن أو متاح / غير متاح ، تنفيذ Mutex.

عد الإشارات - تسمى الإشارات التي تسمح بإحصاء تعسفي للموارد.

افترض أن لدينا 5 طابعات (لنفترض أن طابعة واحدة تقبل مهمة واحدة فقط) وأن لدينا 3 مهام للطباعة. الآن سيتم إعطاء 3 مهام لـ 3 طابعات (واحدة لكل منها). مرة أخرى جاءت 4 وظائف أثناء هذا التقدم. الآن ، من بين طابعتين متاحتين ، تمت جدولة وظيفتين وبقيت لدينا وظيفتان أخريان ، والتي لن تكتمل إلا بعد توفر واحدة من المورد / الطابعة. يمكن اعتبار هذا النوع من الجدولة حسب توفر الموارد على أنه إشارات عد.

لإجراء التزامن باستخدام الإشارات ، فيما يلي الخطوات -

الخطوة 1 - إنشاء إشارة أو الاتصال بإشارة موجودة بالفعل (semget ())

الخطوة 2 - تنفيذ العمليات على الإشارة ، أي تخصيص أو تحرير أو انتظار الموارد (semop ())

الخطوة 3 - إجراء عمليات التحكم في قائمة انتظار الرسائل (semctl ())

الآن ، دعنا نتحقق من ذلك باستخدام مكالمات النظام لدينا.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg)

يقوم استدعاء النظام هذا بإنشاء أو تخصيص مجموعة إشارات System V. يجب تمرير الحجج التالية -

  • الوسيطة الأولى ، المفتاح ، تتعرف على قائمة انتظار الرسائل. يمكن أن يكون المفتاح إما قيمة عشوائية أو قيمة يمكن اشتقاقها من وظيفة المكتبة ftok ().

  • الوسيطة الثانية ، nsems ، تحدد عدد الإشارات. إذا كان الثنائي هو 1 ، فهذا يعني الحاجة إلى مجموعة إشارة واحدة ، وإلا حسب العدد المطلوب لمجموعات السيمافور.

  • الوسيطة الثالثة semflg تحدد إشارة / إشارات الإشارة المطلوبة مثل IPC_CREAT (إنشاء إشارة إذا لم تكن موجودة) أو IPC_EXCL (تُستخدم مع IPC_CREAT لإنشاء إشارة وفشل الاستدعاء ، إذا كانت الإشارة موجودة بالفعل). تحتاج إلى تمرير الأذونات كذلك.

ملاحظة - راجع الأقسام السابقة للحصول على تفاصيل حول الأذونات.

ستعيد هذه المكالمة معرف إشارة صالح (يستخدم لمزيد من استدعاءات الإشارات) على النجاح و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().

العديد من الأخطاء المتعلقة بهذه المكالمة هي EACCESS (تم رفض الإذن) ، EEXIST (قائمة الانتظار موجودة بالفعل لا يمكن إنشاؤها) ، ENOENT (قائمة الانتظار غير موجودة) ، ENOMEM (لا توجد ذاكرة كافية لإنشاء قائمة الانتظار) ، ENOSPC (الحد الأقصى للمجموعات تم تجاوزه) ، إلخ.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *semops, size_t nsemops)

يقوم استدعاء النظام هذا بإجراء العمليات على مجموعات إشارات النظام الخامس ، أي تخصيص الموارد أو انتظار الموارد أو تحرير الموارد. يجب تمرير الحجج التالية -

  • تشير الوسيطة الأولى ، semid ، إلى معرف مجموعة الإشارات التي تم إنشاؤها بواسطة semget ().

  • الوسيطة الثانية ، semops ، هي المؤشر إلى مجموعة من العمليات التي سيتم تنفيذها على مجموعة الإشارات. الهيكل على النحو التالي -

struct sembuf {
   unsigned short sem_num; /* Semaphore set num */
   short sem_op; /* Semaphore operation */
   short sem_flg; /* Operation flags, IPC_NOWAIT, SEM_UNDO */
};

يشير العنصر ، sem_op ، في الهيكل أعلاه ، إلى العملية التي يجب تنفيذها -

  • إذا كان sem_op هو –ve ، فخصص أو احصل على الموارد. يحظر عملية الاستدعاء حتى يتم تحرير موارد كافية بواسطة العمليات الأخرى ، بحيث يمكن تخصيص هذه العملية.

  • إذا كانت sem_op تساوي صفرًا ، فإن عملية الاستدعاء تنتظر أو تنام حتى تصل قيمة الإشارة إلى 0.

  • إذا كانت sem_op تساوي + ve ، فقم بتحرير الموارد.

على سبيل المثال -

Struct sembuf sem_lock = {0، -1، SEM_UNDO} ؛

Struct sembuf sem_unlock = {0، 1، SEM_UNDO} ؛

  • المتغير الثالث ، nsemops ، هو عدد العمليات في تلك المصفوفة.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, …)

يقوم استدعاء النظام هذا بإجراء عملية تحكم لإشارة System V. يجب تمرير الحجج التالية -

  • الوسيطة الأولى ، semid ، هي معرف السيمافور. هذا المعرف هو معرف السيمافور ، وهو القيمة المعادة لاستدعاء نظام semget ().

  • الوسيطة الثانية ، semnum ، هي عدد السيمافور. يتم ترقيم الإشارات من 0.

  • الوسيطة الثالثة ، cmd ، هي الأمر لتنفيذ عملية التحكم المطلوبة على السيمافور.

  • الوسيطة الرابعة من النوع union semun تعتمد على cmd. في حالات قليلة ، لا تنطبق الوسيطة الرابعة.

دعونا نتحقق من اتحاد سيمون -

union semun {
   int val; /* val for SETVAL */
   struct semid_ds *buf; /* Buffer for IPC_STAT and IPC_SET */
   unsigned short *array; /* Buffer for GETALL and SETALL */
   struct seminfo *__buf; /* Buffer for IPC_INFO and SEM_INFO*/
};

هيكل البيانات semid_ds المحدد في sys / sem.h هو كما يلي -

struct semid_ds {
   struct ipc_perm sem_perm; /* Permissions */
   time_t sem_otime; /* Last semop time */
   time_t sem_ctime; /* Last change time */
   unsigned long sem_nsems; /* Number of semaphores in the set */
};

ملاحظة - يرجى الرجوع إلى صفحات الدليل لهياكل البيانات الأخرى.

اتحاد semun arg القيم الصالحة لـ cmd هي -

  • IPC_STAT - ينسخ معلومات القيم الحالية لكل عضو من semid_ds الهيكل إلى الهيكل الذي تم تمريره المشار إليه بواسطة arg.buf. يتطلب هذا الأمر إذن قراءة للإشارة.

  • IPC_SET - يضبط معرف المستخدم ومعرف المجموعة للمالك والأذونات وما إلى ذلك التي يشير إليها الهيكل semid_ds.

  • IPC_RMID - يزيل مجموعة الإشارات.

  • IPC_INFO - إرجاع المعلومات حول حدود ومعلمات السيمافور في البنية semid_ds المشار إليها بواسطة arg .__ buf.

  • SEM_INFO - إرجاع بنية seminfo تحتوي على معلومات حول موارد النظام المستهلكة بواسطة الإشارة.

سيعيد هذا الاستدعاء قيمة (قيمة غير سالبة) اعتمادًا على الأمر الذي تم تمريره. عند النجاح ، تُرجع IPC_INFO و SEM_INFO أو SEM_STAT الفهرس أو المعرف الخاص بأعلى إدخال مستخدم وفقًا لـ Semaphore أو قيمة semncnt لـ GETNCNT أو قيمة sempid لـ GETPID أو قيمة semval لـ GETVAL 0 لعمليات أخرى على النجاح و - 1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().

قبل النظر في الكود ، دعونا نفهم كيفية تنفيذه -

  • إنشاء عمليتين مثل الطفل والوالد

  • قم بإنشاء ذاكرة مشتركة مطلوبة بشكل أساسي لتخزين العداد والأعلام الأخرى للإشارة إلى انتهاء عملية القراءة / الكتابة في الذاكرة المشتركة.

  • يتم زيادة العداد عن طريق العد بواسطة كل من العمليات الأصل والتابعة. يتم تمرير العدد إما كوسيطة سطر أوامر أو يتم استخدامه كوسائط افتراضي (إذا لم يتم تمريره كوسيطة سطر أوامر أو كانت القيمة أقل من 10000). يتم استدعاؤها مع وقت نوم معين لضمان وصول كل من الوالدين والطفل إلى الذاكرة المشتركة في نفس الوقت ، أي بالتوازي.

  • نظرًا لأنه يتم زيادة العداد بخطوات 1 بواسطة كل من الوالد والطفل ، يجب أن تكون القيمة النهائية مضاعفة العداد. نظرًا لأن كلا من العمليات الأم والطفل تؤدي العمليات في نفس الوقت ، لا يتم زيادة العداد كما هو مطلوب. وبالتالي ، نحتاج إلى ضمان اكتمال عملية واحدة متبوعة بعملية أخرى.

  • يتم تنفيذ جميع التطبيقات المذكورة أعلاه في الملف shm_write_cntr.c

  • تحقق مما إذا تم تنفيذ قيمة العداد في ملف shm_read_cntr.c

  • لضمان الاكتمال ، يتم تنفيذ برنامج السيمافور في ملف shm_write_cntr_with_sem.c. قم بإزالة الإشارة بعد الانتهاء من العملية بأكملها (بعد أن تتم القراءة من برنامج آخر)

  • نظرًا لأن لدينا ملفات منفصلة لقراءة قيمة العداد في الذاكرة المشتركة وليس لها أي تأثير من الكتابة ، يظل برنامج القراءة كما هو (shm_read_cntr.c)

  • من الأفضل دائمًا تنفيذ برنامج الكتابة في محطة واحدة وبرنامج القراءة من محطة أخرى. نظرًا لأن البرنامج لا يكمل التنفيذ إلا بعد اكتمال عملية الكتابة والقراءة ، فلا بأس من تشغيل البرنامج بعد تنفيذ برنامج الكتابة بالكامل. سينتظر برنامج الكتابة حتى يتم تشغيل برنامج القراءة ولا ينتهي إلا بعد انتهائه.

برامج بدون إشارات.

/* Filename: shm_write_cntr.c */
#include<stdio.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>

#define SHM_KEY 0x12345
struct shmseg {
   int cntr;
   int write_complete;
   int read_complete;
};
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count);

int main(int argc, char *argv[]) {
   int shmid;
   struct shmseg *shmp;
   char *bufptr;
   int total_count;
   int sleep_time;
   pid_t pid;
   if (argc != 2)
   total_count = 10000;
   else {
      total_count = atoi(argv[1]);
      if (total_count < 10000)
      total_count = 10000;
   }
   printf("Total Count is %d\n", total_count);
   shmid = shmget(SHM_KEY, sizeof(struct shmseg), 0644|IPC_CREAT);

   if (shmid == -1) {
      perror("Shared memory");
      return 1;
   }

   // Attach to the segment to get a pointer to it.
   shmp = shmat(shmid, NULL, 0);
   if (shmp == (void *) -1) {
      perror("Shared memory attach");
      return 1;
   }
   shmp->cntr = 0;
   pid = fork();

   /* Parent Process - Writing Once */
   if (pid > 0) {
      shared_memory_cntr_increment(pid, shmp, total_count);
   } else if (pid == 0) {
      shared_memory_cntr_increment(pid, shmp, total_count);
      return 0;
   } else {
      perror("Fork Failure\n");
      return 1;
   }
   while (shmp->r

قوائم انتظار الرسائل

 

قوائم انتظار الرسائل


قوائم انتظار الرسائل


الإعلانات
Ad by Valueimpression

لماذا نحتاج إلى قوائم انتظار الرسائل عندما يكون لدينا بالفعل ذاكرة مشتركة؟ سيكون لأسباب متعددة ، دعونا نحاول تقسيم هذا إلى عدة نقاط للتبسيط -

  • كما هو مفهوم ، بمجرد تلقي الرسالة من خلال عملية ما ، لن تكون متاحة لأي عملية أخرى. بينما في الذاكرة المشتركة ، تتوفر البيانات لعمليات متعددة للوصول إليها.

  • إذا أردنا التواصل مع تنسيقات الرسائل الصغيرة.

  • يجب حماية بيانات الذاكرة المشتركة من خلال المزامنة عند اتصال عمليات متعددة في نفس الوقت.

  • معدل تكرار الكتابة والقراءة باستخدام الذاكرة المشتركة مرتفع ، فسيكون من الصعب جدًا تنفيذ الوظيفة. لا يستحق فيما يتعلق بالاستخدام في هذا النوع من الحالات.

  • ماذا لو لم تكن جميع العمليات بحاجة إلى الوصول إلى الذاكرة المشتركة ولكن القليل جدًا من العمليات تحتاجها فقط ، فسيكون من الأفضل التنفيذ مع قوائم انتظار الرسائل.

  • إذا أردنا التواصل مع حزم بيانات مختلفة ، فلنقل أن العملية A ترسل نوع الرسالة 1 للمعالجة B ، ونوع الرسالة 10 للمعالجة C ، ونوع الرسالة 20 لمعالجة D. في هذه الحالة ، يكون التنفيذ أسهل مع قوائم انتظار الرسائل. لتبسيط نوع الرسالة المحددة مثل 1 ، 10 ، 20 ، يمكن أن تكون إما 0 أو + ve أو –ve كما هو موضح أدناه.

  • بالطبع ، ترتيب قائمة انتظار الرسائل هو FIFO (First In First Out). الرسالة الأولى المدرجة في قائمة الانتظار هي أول رسالة يتم استردادها.

يعتمد استخدام الذاكرة المشتركة أو قوائم انتظار الرسائل على الحاجة إلى التطبيق ومدى فعالية استخدامه.

يمكن أن يحدث الاتصال باستخدام قوائم انتظار الرسائل بالطرق التالية -

  • الكتابة في الذاكرة المشتركة بعملية واحدة والقراءة من الذاكرة المشتركة بعملية أخرى. كما نعلم ، يمكن أن تتم القراءة من خلال عمليات متعددة أيضًا.

قائمة انتظار الرسائل
  • الكتابة في الذاكرة المشتركة من خلال عملية واحدة مع حزم بيانات مختلفة والقراءة منها بعمليات متعددة ، أي حسب نوع الرسالة.

متعددة قائمة انتظار الرسائل

بعد الاطلاع على معلومات معينة حول قوائم انتظار الرسائل ، حان الوقت الآن للتحقق من استدعاء النظام (النظام الخامس) الذي يدعم قوائم انتظار الرسائل.

لإجراء الاتصال باستخدام قوائم انتظار الرسائل ، فيما يلي الخطوات -

الخطوة 1 - إنشاء قائمة انتظار الرسائل أو الاتصال بقائمة انتظار الرسائل الموجودة بالفعل (msgget ())

الخطوة 2 - الكتابة في قائمة انتظار الرسائل (msgsnd ())

الخطوة 3 - القراءة من قائمة انتظار الرسائل (msgrcv ())

الخطوة 4 - إجراء عمليات التحكم في قائمة انتظار الرسائل (msgctl ())

الآن ، دعونا نتحقق من بناء الجملة وبعض المعلومات حول المكالمات المذكورة أعلاه.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg)

يقوم استدعاء النظام هذا بإنشاء أو تخصيص قائمة انتظار رسائل System V. يجب تمرير الحجج التالية -

  • الوسيطة الأولى ، المفتاح ، تتعرف على قائمة انتظار الرسائل. يمكن أن يكون المفتاح إما قيمة عشوائية أو قيمة يمكن اشتقاقها من وظيفة المكتبة ftok ().

  • الوسيطة الثانية ، shmflg ، تحدد إشارة / إشارات قائمة انتظار الرسائل المطلوبة مثل IPC_CREAT (إنشاء قائمة انتظار الرسائل إذا لم تكن موجودة) أو IPC_EXCL (تُستخدم مع IPC_CREAT لإنشاء قائمة انتظار الرسائل وفشل الاستدعاء ، إذا كانت قائمة انتظار الرسائل موجودة بالفعل). تحتاج إلى تمرير الأذونات كذلك.

ملاحظة - راجع الأقسام السابقة للحصول على تفاصيل حول الأذونات.

ستعيد هذه المكالمة معرف قائمة انتظار رسائل صالح (يستخدم لمزيد من المكالمات لقائمة انتظار الرسائل) عند النجاح و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().

العديد من الأخطاء المتعلقة بهذه المكالمة هي EACCESS (تم رفض الإذن) ، EEXIST (قائمة الانتظار موجودة بالفعل لا يمكن إنشاؤها) ، ENOENT (قائمة الانتظار غير موجودة) ، ENOMEM (لا توجد ذاكرة كافية لإنشاء قائمة الانتظار) ، إلخ.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg)

ترسل مكالمة النظام هذه / تُلحق رسالة في قائمة انتظار الرسائل (النظام الخامس). يجب تمرير الحجج التالية -

  • يتعرف الوسيط الأول ، msgid ، على قائمة انتظار الرسائل ، أي معرف قائمة انتظار الرسائل. يتم استلام قيمة المعرف عند نجاح msgget ()

  • الوسيطة الثانية ، msgp ، هي المؤشر إلى الرسالة ، المرسلة إلى المتصل ، والمحددة في بنية النموذج التالي -

struct msgbuf {
   long mtype;
   char mtext[1];
};

يتم استخدام المتغير mtype للتواصل مع أنواع الرسائل المختلفة ، موضحة بالتفصيل في مكالمة msgrcv (). mtext المتغير عبارة عن مصفوفة أو بنية أخرى يتم تحديد حجمها بواسطة msgsz (قيمة موجبة). إذا لم يتم ذكر حقل mtext ، فسيتم اعتباره رسالة بحجم صفري ، وهو مسموح به.

  • الوسيطة الثالثة msgsz هي حجم الرسالة (يجب أن تنتهي الرسالة بحرف فارغ)

  • الوسيطة الرابعة ، msgflg ، تشير إلى علامات معينة مثل IPC_NOWAIT (تُرجع فورًا عندما لا توجد رسالة في قائمة الانتظار أو MSG_NOERROR (اقتطاع نص الرسالة ، إذا كان أكثر من msgsz بايت)

ستعيد هذه المكالمة 0 عند النجاح و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgrcv(int msgid, const void *msgp, size_t msgsz, long msgtype, int msgflg)

يقوم استدعاء النظام هذا باسترداد الرسالة من قائمة انتظار الرسائل (النظام الخامس). يجب تمرير الحجج التالية -

  • يتعرف الوسيط الأول ، msgid ، على قائمة انتظار الرسائل ، أي معرف قائمة انتظار الرسائل. يتم استلام قيمة المعرف عند نجاح msgget ()

  • الوسيطة الثانية ، msgp ، هي مؤشر الرسالة المستلمة من المتصل. يتم تعريفه في هيكل النموذج التالي -

struct msgbuf {
   long mtype;
   char mtext[1];
};

يستخدم المتغير mtype للتواصل مع أنواع الرسائل المختلفة. mtext المتغير عبارة عن مصفوفة أو بنية أخرى يتم تحديد حجمها بواسطة msgsz (قيمة موجبة). إذا لم يتم ذكر حقل mtext ، فسيتم اعتباره رسالة بحجم صفري ، وهو مسموح به.

  • الوسيطة الثالثة msgsz هي حجم الرسالة المستلمة (يجب أن تنتهي الرسالة بحرف فارغ)

  • الوسيطة fouth ، msgtype ، تشير إلى نوع الرسالة -

    • إذا كانت msgtype تساوي 0 - يقرأ أول رسالة مستلمة في قائمة الانتظار

    • إذا كانت msgtype هي + ve - يقرأ الرسالة الأولى في قائمة الانتظار من النوع msgtype (إذا كان نوع msgtype هو 10 ، فسيقرأ فقط الرسالة الأولى من النوع 10 على الرغم من وجود أنواع أخرى في قائمة الانتظار في البداية)

    • إذا كان msgtype هو –ve - يقرأ الرسالة الأولى من النوع الأدنى أقل من أو يساوي القيمة المطلقة لنوع الرسالة (على سبيل المثال ، إذا كان نوع msgtype هو -5 ، فإنه يقرأ الرسالة الأولى من النوع أقل من 5 ، أي نوع الرسالة من 1 إلى 5)

  • تشير الوسيطة الخامسة ، msgflg ، إلى علامات معينة مثل IPC_NOWAIT (تُرجع فورًا عندما لا توجد رسالة في قائمة الانتظار أو MSG_NOERROR (اقتطاع نص الرسالة إذا كان أكثر من مللي ثانية بايت)

سيعيد هذا الاستدعاء عدد البايتات المتلقاة بالفعل في مصفوفة mtext عند النجاح و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msgid, int cmd, struct msqid_ds *buf)

يقوم استدعاء النظام هذا بإجراء عمليات التحكم في قائمة انتظار الرسائل (النظام الخامس). يجب تمرير الحجج التالية -

  • يتعرف الوسيط الأول ، msgid ، على قائمة انتظار الرسائل ، أي معرف قائمة انتظار الرسائل. يتم استلام قيمة المعرف عند نجاح msgget ()

  • الوسيطة الثانية ، cmd ، هي الأمر لتنفيذ عملية التحكم المطلوبة في قائمة انتظار الرسائل. القيم الصالحة لـ cmd هي -

IPC_STAT - ينسخ معلومات القيم الحالية لكل عضو من عناصر البنية msqid_ds إلى البنية التي تم تمريرها والتي يشير إليها buf. يتطلب هذا الأمر إذن قراءة في قائمة انتظار الرسائل.

IPC_SET - يضبط معرف المستخدم ومعرف المجموعة للمالك والأذونات وما إلى ذلك التي يشير إليها هيكل buf.

IPC_RMID - يزيل قائمة انتظار الرسائل على الفور.

IPC_INFO - يعرض معلومات حول حدود قائمة انتظار الرسائل والمعلمات في الهيكل المشار إليه بواسطة buf ، وهو من النوع Struct msginfo

MSG_INFO - إرجاع بنية msginfo تحتوي على معلومات حول موارد النظام المستهلكة من خلال قائمة انتظار الرسائل.

  • الوسيطة الثالثة ، buf ، هي مؤشر إلى بنية قائمة انتظار الرسائل المسمى Struct msqid_ds. سيتم استخدام قيم هذا الهيكل لأي مجموعة أو الحصول عليها حسب cmd.

سيعيد هذا الاستدعاء القيمة بناءً على الأمر الذي تم تمريره. يؤدي نجاح IPC_INFO و MSG_INFO أو MSG_STAT إلى إرجاع فهرس أو معرف قائمة انتظار الرسائل أو 0 لعمليات أخرى و -1 في حالة الفشل. لمعرفة سبب الفشل ، تحقق من متغير errno أو وظيفة perror ().

بعد الاطلاع على المعلومات الأساسية ومكالمات النظام فيما يتعلق بقوائم انتظار الرسائل ، حان الوقت الآن للتحقق من البرنامج.

دعونا نرى الوصف قبل النظر في البرنامج -

الخطوة 1 - إنشاء عمليتين ، إحداهما للإرسال إلى قائمة انتظار الرسائل (msgq_send.c) والأخرى للاسترداد من قائمة انتظار الرسائل (msgq_recv.c)

الخطوة 2 - إنشاء المفتاح باستخدام وظيفة ftok (). لهذا ، يتم إنشاء ملف msgq.txt مبدئيًا للحصول على مفتاح فريد.

الخطوة 3 - تقوم عملية الإرسال بما يلي.

  • يقرأ إدخال السلسلة من المستخدم

  • يزيل الخط الجديد ، إن وجد

  • يرسل إلى قائمة انتظار الرسائل

  • يكرر العملية حتى نهاية الإدخال (CTRL + D)

  • بمجرد استلام نهاية الإدخال ، يتم إرسال الرسالة "end" للإشارة إلى نهاية العملية

الخطوة 4 - في عملية الاستلام ، يقوم بما يلي.

  • يقرأ الرسالة من قائمة الانتظار
  • يعرض الإخراج
  • إذا كانت الرسالة المستلمة "إنهاء" ، يتم إنهاء العملية والخروج

للتبسيط ، لا نستخدم نوع الرسالة لهذه العينة. أيضًا ، تقوم إحدى العمليات بالكتابة في قائمة الانتظار وعملية أخرى تقرأ من قائمة الانتظار. يمكن تمديد هذا حسب الحاجة ، على سبيل المثال ، من الناحية المثالية ، يمكن كتابة عملية واحدة في قائمة الانتظار وقراءة عمليات متعددة من قائمة الانتظار.

الآن ، دعنا نتحقق من العملية (إرسال الرسالة إلى قائمة الانتظار) - الملف: msgq_send.c

/* Filename: msgq_send.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define PERMS 0644
struct my_msgbuf {
   long mtype;
   char mtext[200];
};

int main(void) {
   struct my_msgbuf buf;
   int msqid;
   int len;
   key_t key;
   system("touch msgq.txt");
   
   if ((key = ftok("msgq.txt", 'B')) == -1) {
      perror("ftok");
      exit(1);
   }
   
   if ((msqid = msgget(key, PERMS | IPC_CREAT)) == -1) {
      perror("msgget");
      exit(1);
   }
   printf("message queue: ready to send messages.\n");
   printf("Enter lines of text, ^D to quit:\n");
   buf.mtype = 1; /* we don't really care in this case */
   
   while(fgets(buf.mtext, sizeof buf.mtext, stdin) != NULL) {
      len = strlen(buf.mtext);
      /* remove newline at end, if it exists */
      if (buf.mtext[len-1] == '\n') buf.mtext[len-1] = '\0';
      if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
      perror("msgsnd");
   }
   strcpy(buf.mtext, "end");
   len = strlen(buf.mtext);
   if (msgsnd(msqid, &buf, len+1, 0) == -1) /* +1 for '\0' */
   perror("msgsnd");
   
   if (msgctl(msqid, IPC_RMID, NULL) == -1) {
      perror("msgctl");
      exit(1);
   }
   printf("message queue: done sending messages.\n");
   return 0;
}

خطوات التجميع والتنفيذ

message queue: ready to send messages.
Enter lines of text, ^D to quit:
this is line 1
this is line 2
message queue: done sending messages.

فيما يلي الكود من عملية استلام الرسالة (استرداد الرسالة من قائمة الانتظار) - الملف: msgq_recv.c

/* Filename: msgq_recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#define PERMS 0644
struct my_msgbuf {
   long mtype;
   char mtext[200];
};

int main(void) {
   struct my_msgbuf buf;
   int msqid;
   int toend;
   key_t key;
   
   if ((key = ftok("msgq.txt", 'B')) == -1) {
      perror("ftok");
      exit(1);
   }
   
   if ((msqid = msgget(key, PERMS)) == -1) { /* connect to the queue */
      perror("msgget");
      exit(1);
   }
   printf("message queue: ready to receive messages.\n");
   
   for(;;) { /* normally receiving never ends but just to make conclusion 
             /* this program ends wuth string of end */
      if (msgrcv(msqid, &buf, sizeof(buf.mtext), 0, 0) == -1) {
         perror("msgrcv");
         exit(1);
      }
      printf("recvd: \"%s\"\n", buf.mtext);
      toend = strcmp(buf.mtext,"end");
      if (toend == 0)
      break;
   }
   printf("message queue: done receiving messages.\n");
   system("rm msgq.txt");
   return 0;
}

خطوات التجميع والتنفيذ

message queue: ready to receive messages.
recvd: "this is line 1"
recvd: "this is line 2"
recvd: "end"
message queue: done receiving mes