การสื่อสารระหว่างกระบวนการ - Semaphores

คำถามแรกที่อยู่ในใจคือทำไมเราต้องมีเซมาโฟร์? คำตอบง่ายๆเพื่อปกป้องภูมิภาคสำคัญ / ร่วมกันระหว่างกระบวนการต่างๆ

สมมติว่ากระบวนการต่างๆกำลังใช้รหัสภูมิภาคเดียวกันและหากทุกคนต้องการเข้าถึงแบบขนานผลลัพธ์จะซ้อนทับกัน ตัวอย่างเช่นผู้ใช้หลายคนกำลังใช้เครื่องพิมพ์เพียงเครื่องเดียว (ส่วนทั่วไป / ส่วนสำคัญ) เช่นผู้ใช้ 3 คนรับงาน 3 งานในเวลาเดียวกันหากงานทั้งหมดเริ่มต้นพร้อมกันเอาต์พุตของผู้ใช้หนึ่งรายการจะซ้อนทับกับอีกเครื่องหนึ่ง ดังนั้นเราจำเป็นต้องป้องกันโดยใช้เซมาโฟเรสนั่นคือล็อกส่วนวิกฤตเมื่อกระบวนการหนึ่งกำลังทำงานและปลดล็อกเมื่อเสร็จสิ้น สิ่งนี้จะเกิดขึ้นซ้ำสำหรับผู้ใช้ / กระบวนการแต่ละคนเพื่อไม่ให้งานหนึ่งทับซ้อนกับงานอื่น

โดยทั่วไป semaphores แบ่งออกเป็นสองประเภท -

Binary Semaphores - มีเพียงสองสถานะ 0 & 1 เท่านั้น ได้แก่ ล็อก / ปลดล็อกหรือพร้อมใช้งาน / ไม่พร้อมใช้งานการใช้งาน Mutex

Counting Semaphores - Semaphores ที่อนุญาตให้มีการนับทรัพยากรโดยพลการเรียกว่าการนับ semaphores

สมมติว่าเรามีเครื่องพิมพ์ 5 เครื่อง (ให้เข้าใจสมมติว่าเครื่องพิมพ์ 1 เครื่องรับงานได้ 1 งานเท่านั้น) และมีงานให้พิมพ์ 3 งาน ตอนนี้จะได้รับ 3 งานสำหรับเครื่องพิมพ์ 3 เครื่อง (งานละ 1 เครื่อง) อีก 4 งานเข้ามาในขณะที่กำลังดำเนินการ ตอนนี้มีเครื่องพิมพ์จาก 2 เครื่องมีกำหนดงาน 2 งานและเราเหลืองานอีก 2 งานซึ่งจะเสร็จสมบูรณ์หลังจากที่มีทรัพยากร / เครื่องพิมพ์เครื่องใดเครื่องหนึ่งเท่านั้น การจัดกำหนดการแบบนี้ตามความพร้อมของทรัพยากรสามารถดูได้ว่าเป็นการนับเซมาโฟร์

ในการซิงโครไนซ์โดยใช้เซมาโฟร์ให้ทำตามขั้นตอนต่อไปนี้ -

Step 1 - สร้างสัญญาณหรือเชื่อมต่อกับสัญญาณที่มีอยู่แล้ว (semget ())

Step 2 - ดำเนินการกับสัญญาณเช่นจัดสรรหรือปล่อยหรือรอทรัพยากร (semop ())

Step 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 ระบุจำนวนของ semaphores ถ้าไบนารีเป็น 1 แสดงว่าต้องการชุดเซมาฟอร์ 1 ชุดหรือตามจำนวนชุดเซมาฟอร์ที่ต้องการ

  • อาร์กิวเมนต์ที่สาม semflg ระบุแฟล็ก / s เซมาฟอร์ที่ต้องการเช่น IPC_CREAT (การสร้างเซมาฟอร์หากไม่มีอยู่) หรือ IPC_EXCL (ใช้กับ IPC_CREAT เพื่อสร้างเซมาฟอร์และการเรียกล้มเหลวหากมีเซมาฟอร์อยู่แล้ว) จำเป็นต้องผ่านการอนุญาตเช่นกัน

Note - อ้างอิงส่วนก่อนหน้าสำหรับรายละเอียดเกี่ยวกับการอนุญาต

การเรียกนี้จะส่งคืนตัวระบุเซมาฟอร์ที่ถูกต้อง (ใช้สำหรับการเรียกเซมาโฟร์ต่อไป) เมื่อสำเร็จและ -1 ในกรณีที่ล้มเหลว หากต้องการทราบสาเหตุของความล้มเหลวให้ตรวจสอบด้วยฟังก์ชัน errno variable หรือ 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)

การเรียกระบบนี้ดำเนินการบนชุดเซมาฟอร์ System V ได้แก่ จัดสรรทรัพยากรรอทรัพยากรหรือปลดปล่อยทรัพยากร ต้องส่งผ่านข้อโต้แย้งต่อไปนี้ -

  • อาร์กิวเมนต์แรก 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 ปล่อยทรัพยากร

ตัวอย่างเช่น -

โครงสร้าง sembuf sem_lock = {0, -1, SEM_UNDO};

โครงสร้าง 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 คือตัวระบุของเซมาฟอร์ id นี้คือตัวระบุเซมาฟอร์ซึ่งเป็นค่าส่งคืนของการเรียกระบบ semget ()

  • อาร์กิวเมนต์ที่สอง semnum คือจำนวนของสัญญาณ semaphores มีจำนวนตั้งแต่ 0

  • อาร์กิวเมนต์ที่สาม cmd เป็นคำสั่งเพื่อดำเนินการควบคุมที่จำเป็นบนเซมาฟอร์

  • อาร์กิวเมนต์ที่สี่ประเภทยูเนี่ยนเซมุนขึ้นอยู่กับ 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 */
};

Note - โปรดดูหน้าคู่มือสำหรับโครงสร้างข้อมูลอื่น ๆ

สหภาพเซมุนอาร์กิวเมนต์; ค่าที่ถูกต้องสำหรับ cmd คือ -

  • IPC_STAT- คัดลอกข้อมูลของค่าปัจจุบันของสมาชิกแต่ละคนของ struct semid_ds ไปยังโครงสร้างที่ส่งผ่านที่ชี้โดย arg.buf คำสั่งนี้ต้องการสิทธิ์ในการอ่านสำหรับเซมาฟอร์

  • IPC_SET - ตั้งค่า ID ผู้ใช้ ID กลุ่มของเจ้าของสิทธิ์ ฯลฯ ที่โครงสร้าง semid_ds ชี้ให้เห็น

  • IPC_RMID - ลบชุด semaphores

  • IPC_INFO - ส่งกลับข้อมูลเกี่ยวกับขีด จำกัด ของสัญญาณและพารามิเตอร์ในโครงสร้าง semid_ds ที่ชี้โดย arg .__ buf

  • SEM_INFO - ส่งกลับโครงสร้าง seminfo ที่มีข้อมูลเกี่ยวกับทรัพยากรระบบที่ใช้โดยเซมาฟอร์

การเรียกนี้จะคืนค่า (ค่าที่ไม่ใช่ค่าลบ) ขึ้นอยู่กับคำสั่งที่ส่ง เมื่อประสบความสำเร็จ IPC_INFO และ SEM_INFO หรือ SEM_STAT จะส่งกลับดัชนีหรือตัวระบุของรายการที่ใช้สูงสุดตาม Semaphore หรือค่าของ semncnt สำหรับ GETPID หรือค่าของ sempid สำหรับ GETPID หรือค่าของ semval สำหรับ GETVAL 0 สำหรับการดำเนินการอื่น ๆ ที่ประสบความสำเร็จและ - 1 ในกรณีที่ล้มเหลว หากต้องการทราบสาเหตุของความล้มเหลวให้ตรวจสอบด้วยฟังก์ชัน errno variable หรือ perror ()

ก่อนที่จะดูโค้ดให้เราทำความเข้าใจกับการนำไปใช้งาน -

  • สร้างสองกระบวนการพูดว่าเด็กและผู้ปกครอง

  • สร้างหน่วยความจำแบบแบ่งใช้ส่วนใหญ่ที่จำเป็นในการจัดเก็บตัวนับและแฟล็กอื่น ๆ เพื่อระบุการสิ้นสุดกระบวนการอ่าน / เขียนลงในหน่วยความจำแบบแบ่งใช้

  • ตัวนับจะเพิ่มขึ้นโดยการนับโดยกระบวนการทั้งแม่และลูก การนับจะถูกส่งผ่านเป็นอาร์กิวเมนต์บรรทัดคำสั่งหรือใช้เป็นค่าเริ่มต้น (หากไม่ผ่านเป็นอาร์กิวเมนต์บรรทัดคำสั่งหรือค่าน้อยกว่า 10,000) เรียกว่ามีเวลานอนที่แน่นอนเพื่อให้แน่ใจว่าทั้งผู้ปกครองและเด็กเข้าถึงหน่วยความจำที่ใช้ร่วมกันในเวลาเดียวกันเช่นแบบขนาน

  • เนื่องจากตัวนับจะเพิ่มขึ้นในขั้นตอนที่ 1 โดยทั้งแม่และลูกค่าสุดท้ายควรเป็นสองเท่าของตัวนับ เนื่องจากกระบวนการทั้งแม่และลูกดำเนินการในเวลาเดียวกันตัวนับจะไม่เพิ่มขึ้นตามที่ต้องการ ดังนั้นเราจำเป็นต้องตรวจสอบให้แน่ใจว่ากระบวนการหนึ่งเสร็จสมบูรณ์ตามด้วยกระบวนการอื่น ๆ

  • การใช้งานทั้งหมดข้างต้นดำเนินการในไฟล์ shm_write_cntr.c

  • ตรวจสอบว่ามีการใช้ค่าตัวนับในไฟล์ shm_read_cntr.c หรือไม่

  • เพื่อให้แน่ใจว่าเสร็จสมบูรณ์โปรแกรม semaphore จะถูกนำไปใช้ในไฟล์ shm_write_cntr_with_sem.c ลบสัญญาณหลังจากเสร็จสิ้นกระบวนการทั้งหมด (หลังจากอ่านเสร็จจากโปรแกรมอื่น)

  • เนื่องจากเรามีไฟล์แยกต่างหากเพื่ออ่านค่าของตัวนับในหน่วยความจำที่ใช้ร่วมกันและไม่มีผลใด ๆ จากการเขียนโปรแกรมการอ่านยังคงเหมือนเดิม (shm_read_cntr.c)

  • การรันโปรแกรมเขียนในเทอร์มินัลเดียวและอ่านโปรแกรมจากเทอร์มินัลอื่นจะดีกว่าเสมอ เนื่องจากโปรแกรมจะดำเนินการเสร็จสิ้นหลังจากกระบวนการเขียนและการอ่านเสร็จสมบูรณ์แล้วจึงสามารถเรียกใช้โปรแกรมได้หลังจากเรียกใช้โปรแกรมเขียนอย่างสมบูรณ์ โปรแกรมเขียนจะรอจนกว่าโปรแกรมอ่านจะทำงานและเสร็จสิ้นหลังจากเสร็จสิ้นเท่านั้น

โปรแกรมที่ไม่มี semaphores

/* 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->read_complete != 1)
   sleep(1);

   if (shmdt(shmp) == -1) {
      perror("shmdt");
      return 1;
   }

   if (shmctl(shmid, IPC_RMID, 0) == -1) {
      perror("shmctl");
      return 1;
   }
   printf("Writing Process: Complete\n");
   return 0;
}

/* Increment the counter of shared memory by total_count in steps of 1 */
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count) {
   int cntr;
   int numtimes;
   int sleep_time;
   cntr = shmp->cntr;
   shmp->write_complete = 0;
   if (pid == 0)
   printf("SHM_WRITE: CHILD: Now writing\n");
   else if (pid > 0)
   printf("SHM_WRITE: PARENT: Now writing\n");
   //printf("SHM_CNTR is %d\n", shmp->cntr);
   
   /* Increment the counter in shared memory by total_count in steps of 1 */
   for (numtimes = 0; numtimes < total_count; numtimes++) {
      cntr += 1;
      shmp->cntr = cntr;
      
      /* Sleeping for a second for every thousand */
      sleep_time = cntr % 1000;
      if (sleep_time == 0)
      sleep(1);
   }
   
   shmp->write_complete = 1;
   if (pid == 0)
   printf("SHM_WRITE: CHILD: Writing Done\n");
   else if (pid > 0)
   printf("SHM_WRITE: PARENT: Writing Done\n");
   return;
}

ขั้นตอนการรวบรวมและดำเนินการ

Total Count is 10000
SHM_WRITE: PARENT: Now writing
SHM_WRITE: CHILD: Now writing
SHM_WRITE: PARENT: Writing Done
SHM_WRITE: CHILD: Writing Done
Writing Process: Complete

ตอนนี้ให้เราตรวจสอบโปรแกรมการอ่านหน่วยความจำที่ใช้ร่วมกัน

/* Filename: shm_read_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>

#define SHM_KEY 0x12345
struct shmseg {
   int cntr;
   int write_complete;
   int read_complete;
};

int main(int argc, char *argv[]) {
   int shmid, numtimes;
   struct shmseg *shmp;
   int total_count;
   int cntr;
   int sleep_time;
   if (argc != 2)
   total_count = 10000;
   
   else {
      total_count = atoi(argv[1]);
      if (total_count < 10000)
      total_count = 10000;
   }
   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;
   }
   
   /* Read the shared memory cntr and print it on standard output */
   while (shmp->write_complete != 1) {
      if (shmp->cntr == -1) {
         perror("read");
         return 1;
      }
      sleep(3);
   }
   printf("Reading Process: Shared Memory: Counter is %d\n", shmp->cntr);
   printf("Reading Process: Reading Done, Detaching Shared Memory\n");
   shmp->read_complete = 1;
   
   if (shmdt(shmp) == -1) {
      perror("shmdt");
      return 1;
   }
   printf("Reading Process: Complete\n");
   return 0;
}

ขั้นตอนการรวบรวมและดำเนินการ

Reading Process: Shared Memory: Counter is 11000
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete

หากคุณสังเกตผลลัพธ์ข้างต้นตัวนับควรเป็น 20000 อย่างไรก็ตามเนื่องจากก่อนที่จะเสร็จสิ้นงานกระบวนการหนึ่งกระบวนการอื่น ๆ ก็กำลังประมวลผลแบบขนานเช่นกันค่าตัวนับจึงไม่เป็นไปตามที่คาดไว้ ผลลัพธ์จะแตกต่างกันไปในแต่ละระบบและจะแตกต่างกันไปตามแต่ละการดำเนินการ เพื่อให้แน่ใจว่ากระบวนการทั้งสองทำงานได้หลังจากเสร็จสิ้นภารกิจหนึ่งควรดำเนินการโดยใช้กลไกการซิงโครไนซ์

ตอนนี้ให้เราตรวจสอบแอปพลิเคชันเดียวกันโดยใช้ semaphores

Note - โปรแกรมการอ่านยังคงเหมือนเดิม

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

#define SHM_KEY 0x12345
#define SEM_KEY 0x54321
#define MAX_TRIES 20

struct shmseg {
   int cntr;
   int write_complete;
   int read_complete;
};
void shared_memory_cntr_increment(int, struct shmseg*, int);
void remove_semaphore();

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->read_complete != 1)
   sleep(1);
   
   if (shmdt(shmp) == -1) {
      perror("shmdt");
      return 1;
   }
   
   if (shmctl(shmid, IPC_RMID, 0) == -1) {
      perror("shmctl");
      return 1;
   }
   printf("Writing Process: Complete\n");
   remove_semaphore();
   return 0;
}

/* Increment the counter of shared memory by total_count in steps of 1 */
void shared_memory_cntr_increment(int pid, struct shmseg *shmp, int total_count) {
   int cntr;
   int numtimes;
   int sleep_time;
   int semid;
   struct sembuf sem_buf;
   struct semid_ds buf;
   int tries;
   int retval;
   semid = semget(SEM_KEY, 1, IPC_CREAT | IPC_EXCL | 0666);
   //printf("errno is %d and semid is %d\n", errno, semid);
   
   /* Got the semaphore */
   if (semid >= 0) {
      printf("First Process\n");
      sem_buf.sem_op = 1;
      sem_buf.sem_flg = 0;
      sem_buf.sem_num = 0;
      retval = semop(semid, &sem_buf, 1);
      if (retval == -1) {
         perror("Semaphore Operation: ");
         return;
      }
   } else if (errno == EEXIST) { // Already other process got it
      int ready = 0;
      printf("Second Process\n");
      semid = semget(SEM_KEY, 1, 0);
      if (semid < 0) {
         perror("Semaphore GET: ");
         return;
      }
      
      /* Waiting for the resource */
      sem_buf.sem_num = 0;
      sem_buf.sem_op = 0;
      sem_buf.sem_flg = SEM_UNDO;
      retval = semop(semid, &sem_buf, 1);
      if (retval == -1) {
         perror("Semaphore Locked: ");
         return;
      }
   }
   sem_buf.sem_num = 0;
   sem_buf.sem_op = -1; /* Allocating the resources */
   sem_buf.sem_flg = SEM_UNDO;
   retval = semop(semid, &sem_buf, 1);
   
   if (retval == -1) {
      perror("Semaphore Locked: ");
      return;
   }
   cntr = shmp->cntr;
   shmp->write_complete = 0;
   if (pid == 0)
   printf("SHM_WRITE: CHILD: Now writing\n");
   else if (pid > 0)
   printf("SHM_WRITE: PARENT: Now writing\n");
   //printf("SHM_CNTR is %d\n", shmp->cntr);
   
   /* Increment the counter in shared memory by total_count in steps of 1 */
   for (numtimes = 0; numtimes < total_count; numtimes++) {
      cntr += 1;
      shmp->cntr = cntr;
      /* Sleeping for a second for every thousand */
      sleep_time = cntr % 1000;
      if (sleep_time == 0)
      sleep(1);
   }
   shmp->write_complete = 1;
   sem_buf.sem_op = 1; /* Releasing the resource */
   retval = semop(semid, &sem_buf, 1);
   
   if (retval == -1) {
      perror("Semaphore Locked\n");
      return;
   }
   
   if (pid == 0)
      printf("SHM_WRITE: CHILD: Writing Done\n");
      else if (pid > 0)
      printf("SHM_WRITE: PARENT: Writing Done\n");
      return;
}
   
void remove_semaphore() {
   int semid;
   int retval;
   semid = semget(SEM_KEY, 1, 0);
      if (semid < 0) {
         perror("Remove Semaphore: Semaphore GET: ");
         return;
      }
   retval = semctl(semid, 0, IPC_RMID);
   if (retval == -1) {
      perror("Remove Semaphore: Semaphore CTL: ");
      return;
   }
   return;
}

ขั้นตอนการรวบรวมและดำเนินการ

Total Count is 10000
First Process
SHM_WRITE: PARENT: Now writing
Second Process
SHM_WRITE: PARENT: Writing Done
SHM_WRITE: CHILD: Now writing
SHM_WRITE: CHILD: Writing Done
Writing Process: Complete

ตอนนี้เราจะตรวจสอบค่าตัวนับตามขั้นตอนการอ่าน

ขั้นตอนการดำเนินการ

Reading Process: Shared Memory: Counter is 20000
Reading Process: Reading Done, Detaching Shared Memory
Reading Process: Complete