1, Experimental time
Thursday, May 6, 2021, week 10
2, Experimental purpose
Deepen the understanding of the concepts of concurrent collaborative process synchronization and mutual exclusion, observe and experience the effects of concurrent process synchronization and mutual exclusion, and analyze and study the practical solutions to the classical process synchronization and mutual exclusion problems. Understand the usage of IPC process synchronization tool in Linux system, and practice the programming and debugging technology of synchronization and mutually exclusive operation of concurrent collaborative processes.
3, Example experiment
In this experiment, the example experiment is extremely important. It can be said that if you understand the example experiment clearly, the independent experiment can be done quickly. Most of the code of the independent experiment is copied and pasted
IPC in example experiment h
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/msg.h> #define BUFSZ 256 // Establish or obtain the prototype description of a set of functions of ipc int get_ipc_id(char *proc_file,key_t key); char *set_shm(key_t shm_key,int shm_num,int shm_flag); int set_msq(key_t msq_key,int msq_flag); int set_sem(key_t sem_key,int sem_val,int sem_flag); int down(int sem_id); int up(int sem_id); /*Community for signal lamp control*/ typedef union semuns { int val; } Sem_uns; /* Message structure */ typedef struct msgbuf { long mtype; char mtext[1]; } Msg_buf; // The production consumer shared buffer is its related variable key_t buff_key; int buff_num; char *buff_ptr; // Shared pointer of the producer to the product location key_t pput_key; int pput_num; int *pput_ptr; // The consumer takes the shared pointer of the product location key_t cget_key; int cget_num; int *cget_ptr; // Producer related semaphores key_t prod_key; key_t pmtx_key; int prod_sem; int pmtx_sem; // Consumer related semaphores key_t cons_key; key_t cmtx_key; int cons_sem; int cmtx_sem; int sem_val; int sem_flg; int shm_flg;
In the header file, we should focus on understanding the functions of down and up functions, as well as the declaration and function of semaphores
For example, the following semaphores are declared in the header file:
In the following independent experiments, we can also define and use our own semaphores
// Producer related semaphores key_t prod_key; key_t pmtx_key; int prod_sem; int pmtx_sem; // Consumer related semaphores key_t cons_key; key_t cmtx_key; int cons_sem; int cmtx_sem; int sem_val; int sem_flg; int shm_flg;
ipc.c Documents
This file is mainly the specific implementation of the method in the header file above. Finally, when the independent experiment is carried out, you can directly copy and paste it without any change. When looking at the example experiment, it is required to understand the function of each function clearly, and the specific content of the function does not need to be mastered
#include "ipc.h" /* * get_ipc_id() Get the id number of IPC from the / proc/sysvipc / file system * pfile: The IPC files in the corresponding / proc/sysvipc / directory are * msg-Message queue, sem semaphore, shm shared memory * key: The key value corresponding to the id number of the IPC to be obtained */ int get_ipc_id(char *proc_file, key_t key) { FILE *pf; int i, j; char line[BUFSZ], colum[BUFSZ]; if((pf = fopen(proc_file, "r")) == NULL) { perror("Proc file not open"); exit(EXIT_FAILURE); } fgets(line, BUFSZ, pf); while(!feof(pf)) { i = j = 0; fgets(line, BUFSZ, pf); while(line[i] == ' ') i++; while(line[i] != ' ') colum[j++] = line[i++]; colum[j] = '\0'; if(atoi(colum) != key) continue; j = 0; while(line[i] == ' ') i++; while(line[i] !=' ') colum[j++] = line[i++]; colum[j] = '\0'; i = atoi(colum); fclose(pf); return i; } fclose(pf); return -1; } /* * down/up operation on signal lamp * semid:Semaphore array identifier * semnum:Semaphore array subscript * buf:Structure of operating signal lamp */ int down(int sem_id) { struct sembuf buf; buf.sem_op = -1; buf.sem_num = 0; buf.sem_flg = SEM_UNDO; if((semop(sem_id, &buf, 1)) < 0) { perror("down error "); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } int up(int sem_id) { struct sembuf buf; buf.sem_op = 1; buf.sem_num = 0; buf.sem_flg = SEM_UNDO; if((semop(sem_id, &buf, 1)) < 0) { perror("up error "); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } /* * set_sem Function to establish a semaphore with n semaphores * If the establishment is successful, the identifier SEM of a semaphore array is returned_ id * Input parameters: * sem_key Key value of semaphore array * sem_val Number of semaphores in semaphore array * sem_flag Access rights of arrays such as signals */ int set_sem(key_t sem_key,int sem_val,int sem_flg) { int sem_id; Sem_uns sem_arg; // Tested by SEM_ Has the semaphore array identified by key been established if((sem_id = get_ipc_id("/proc/sysvipc/sem", sem_key)) < 0) { // semget creates a new signal lamp, and its label returns to sem_id if((sem_id = semget(sem_key, 1, sem_flg)) < 0) { perror("semaphore create error"); exit(EXIT_FAILURE); } // Set the initial value of the signal lamp sem_arg.val = sem_val; if(semctl(sem_id, 0, SETVAL, sem_arg) < 0) { perror("semaphore set error"); exit(EXIT_FAILURE); } } return sem_id; } /* * set_shm Function to create a shared memory area with n bytes * If the establishment is successful, a pointer SHM to the first address of the memory area is returned_ buf * Input parameters: * shm_key Key value of shared memory * shm_val Length of shared memory bytes * shm_flag Access to shared memory */ char* set_shm(key_t shm_key,int shm_num,int shm_flg) { int i, shm_id; char * shm_buf; // Test by SHM_ Whether the shared memory area identified by key has been established if((shm_id = get_ipc_id("/proc/sysvipc/shm", shm_key)) < 0) { // shmget creates a new one with the length of shm_num bytes of shared memory, and its label is returned to shm_id if((shm_id = shmget(shm_key,shm_num,shm_flg)) <0) { perror("shareMemory set error"); exit(EXIT_FAILURE); } // shmat will be controlled by SHM_ The shared memory identified by ID is attached to the pointer shm_buf if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0) { perror("get shareMemory error"); exit(EXIT_FAILURE); } for(i = 0; i < shm_num; i++) shm_buf[i] = 0; //Initial 0 } // shm_ The shared memory area identified by key has been established and will be used by SHM_ The shared memory identified by ID is attached to the pointer shm_buf if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0) { perror("get shareMemory error"); exit(EXIT_FAILURE); } return shm_buf; } /* * set_msq Function to establish a message queue * If the establishment is successful, an identifier MSQ of the message queue is returned_ id * Input parameters: * msq_key Key value of message queue * msq_flag Access rights of message queue */ int set_msq(key_t msq_key,int msq_flg) { int msq_id; //Test by MSQ_ Whether the message queue identified by key has been established if((msq_id = get_ipc_id("/proc/sysvipc/msg", msq_key)) < 0) { //msgget creates a new message queue and returns its label to msq_id if((msq_id = msgget(msq_key,msq_flg)) < 0) { perror("messageQueue set error"); exit(EXIT_FAILURE); } } return msq_id; }
producer.c
This document mainly describes the process of producers producing goods
Among them, the pseudo code of circular production is as follows
while(1) { //If the buffer is full, production is no longer possible wait(full); //If another producer is producing, wait wait(mutex_producer); yield a product signal(mutex_producer); //Awaken consumers signal(consumer); }
The following code uses IPC The down and up functions defined in H realize the functions of wait and signal, and the principle is the same
It should also be noted that many variables are used before entering the while loop, and these variables are used to obtain the value of the semaphore, which will be used in the code for writing independent experiments later
#include "ipc.h" int main(int argc, char *argv[]) { int rate; // You can specify the number of sleep seconds of a process in the first parameter of the command line to mediate the execution speed of the process if(argv[1] != NULL) rate = atoi(argv[1]); else rate = 3; // Not specified as 3 seconds // Variables used by shared memory buff_key = 101; // The key value assigned to the buffer buff_num = 8; // Length of buffer pput_key = 102; // The producer puts the key value of the product pointer pput_num = 1; // Number of pointers shm_flg = IPC_CREAT | 0644; // Shared memory read and write permissions // Get the shared memory used by the buffer, buff_ptr points to the first address of the buffer buff_ptr = (char*)set_shm(buff_key, buff_num, shm_flg); // Get the producer's product placement pointer pput_ptr pput_ptr = (int*)set_shm(pput_key, pput_num, shm_flg); // Variables used by semaphores prod_key = 201; // Producer synchronization light key value pmtx_key = 202; // Producer mutually exclusive semaphore key value cons_key = 301; // Consumer sync light key value cmtx_key = 302; // Consumer mutually exclusive semaphore key value sem_flg = IPC_CREAT | 0644; // The initial value of producer synchronization signal is set as the maximum available amount of buffer sem_val = buff_num; // Obtain the producer synchronization signal lamp, and save the reference ID prod_sem prod_sem = set_sem(prod_key,sem_val,sem_flg); // The initial value of the synchronization signal lamp is set to 0 when there is no product available for the consumer sem_val = 0; // Get the consumer synchronization signal light, and save the reference ID in cons_sem cons_sem = set_sem(cons_key,sem_val,sem_flg); // The initial value of producer mutually exclusive signal lamp is 1 sem_val = 1; // Get the producer mutually exclusive semaphore, and store the reference ID in pmtx_sem pmtx_sem = set_sem(pmtx_key,sem_val,sem_flg); // Loop execution simulates the continuous release of products by producers while(1) { // If the buffer is full, the producer is blocked down(prod_sem); // If another producer is releasing products, this producer is blocked down(pmtx_sem); // Simulate the producer to put the product in the form of writing one character, and report the process number, put characters and storage location buff_ptr[*pput_ptr] = 'A' + *pput_ptr; sleep(rate); printf("%d producer put: %c to Buffer[%d]\n",getpid(),buff_ptr[*pput_ptr],*pput_ptr); // The storage position moves down circularly *pput_ptr = (*pput_ptr+1) % buff_num; // Wake up blocked producers up(pmtx_sem); // Wake up blocked consumers up(cons_sem); } return EXIT_SUCCESS; }
consumer.c
This document mainly describes the process that consumers get what producers produce from the buffer
Among them, the microcode obtained by loop is
The following code uses IPC The down and up functions defined in H realize the functions of wait and signal, and the principle is the same
while(1) { // If no product is blocked by consumers wait(consumer); // If another consumer is taking the product, this consumer is blocked down(mutex_consumer); Consumer goods // Wake up blocked consumers up(mutex_consumer); // Wake up blocked producers up(full); }
#include "ipc.h" int main(int argc,char *argv[]) { int rate; // You can specify the number of sleep seconds of a process in the first parameter of the command line to mediate the execution speed of the process if(argv[1] != NULL) rate = atoi(argv[1]); else rate = 3; // Not specified as 3 seconds // Variables used by shared memory buff_key = 101; // The key value assigned to the buffer buff_num = 8; // Given buffer length cget_key = 103; // The consumer takes the key value of the product pointer cget_num = 1; // Number of pointers shm_flg = IPC_CREAT | 0644; //Shared memory read and write permissions // Get the shared memory used by the buffer, buff_ptr points to the first address of the buffer buff_ptr = (char *)set_shm(buff_key,buff_num,shm_flg); // Get consumer product pointer, cget_ptr points to index address cget_ptr = (int *)set_shm(cget_key,cget_num,shm_flg); // Variables used by semaphores prod_key = 201; // Producer synchronization light key value pmtx_key = 202; // Producer mutually exclusive semaphore key value cons_key = 301; // Consumer key value synchronization signal cmtx_key = 302; // Consumer mutually exclusive semaphore key value sem_flg = IPC_CREAT | 0644; // Operation authority of signal lamp // The initial value of producer synchronization signal is set as the maximum available amount of buffer sem_val = buff_num; // Obtain the producer synchronization signal lamp, and save the reference ID prod_sem prod_sem = set_sem(prod_key,sem_val,sem_flg); // The initial value of the synchronization signal lamp is set to 0 when there is no product available for the consumer sem_val = 0; // Get the consumer synchronization signal light, and save the reference ID in cons_sem cons_sem = set_sem(cons_key,sem_val,sem_flg); // The initial value of consumer mutually exclusive signal lamp is 1 sem_val = 1; // Get the mutually exclusive semaphore of the consumer, and store the reference ID in pmtx_sem cmtx_sem = set_sem(cmtx_key,sem_val,sem_flg); // Circular execution simulates that consumers constantly take products while(1) { // If no product is blocked by consumers down(cons_sem); // If another consumer is taking the product, this consumer is blocked down(cmtx_sem); // Simulate the consumer to take the product in the form of reading one character, and report the process number, the obtained characters and the reading position sleep(rate); printf("%d consumer get: %c from Buffer[%d]\n", getpid(), buff_ptr[*cget_ptr], *cget_ptr); // Read position cycle down *cget_ptr = (*cget_ptr+1) % buff_num; // Wake up blocked consumers up(cmtx_sem); // Wake up blocked producers up(prod_sem); } return EXIT_SUCCESS; }
makefile file
hdrs = ipc.h opts = -g -c c_src = consumer.c ipc.c c_obj = consumer.o ipc.o p_src = producer.c ipc.c p_obj = producer.o ipc.o all: producer consumer consumer: $(c_obj) gcc $(c_obj) -o consumer consumer.o: $(c_src) $(hdrs) gcc $(opts) $(c_src) producer: $(p_obj) gcc $(p_obj) -o producer producer.o: $(p_src) $(hdrs) gcc $(opts) $(p_src) clean: rm consumer producer *.o
Experimental results of example experiments
4, Independent experiment
4.1 experimental description
Smokers. Suppose there are three smoker processes in a system, and each smoker continuously smokes cigarettes and smokes. A smoker needs three materials to roll up and smoke a cigarette: tobacco, paper and glue. One smoker has tobacco, one has paper and the other has glue. There are also two supplier processes in the system, which supply all three materials indefinitely, but only two of the three materials are provided in turn at a time. The smoker who gets the missing two materials will signal the supplier to continue to provide the other two materials after rolling up and smoking a cigarette. This process is repeated. Please program with the IPC synchronization mechanism described above to realize the functions required by this problem.
First of all, we need to clarify the meaning of the topic, which tells us the following points
- There are two producers that loop materials into the buffer. My understanding is that the array length of the buffer is 1, and the two producers put two different materials into the buffer in turn. For example, the first time producer A puts tobacco and paper into the buffer, the second time producer B puts tobacco and glue into the buffer, and so on.
- Three smokers. Each of the three smokers has one fixed thing. This thing is glue, paper or tobacco, while the other two things are obtained from the buffer. If they are obtained, they smoke. If not, they wait
- There is another understanding about producers. The buffer length is 2. Two producers put materials into buffer[0] and buffer[1] respectively. Two producers put materials in turn. The materials put in cannot be the same. Then the smoker takes the corresponding material from the buffer zone.
Producers and smokers
Producers and smokers (consumers) need the following semaphores, which need to be in IPC Defined in H
// Producer related semaphores //Semaphore with full buffer key_t full_key; //The semaphore that ensures the mutual exclusion of producers when releasing materials key_t mutex_key; int full_sem; int mutex_sem; // Consumer related semaphores //There's glue and grass key_t GlueGrass_key; //There's glue and paper key_t GluePaper_key; //There is paper and grass key_t PaperGrass_key; int GlueGrass_sem; int GluePaper_sem; int PaperGrass_sem;
The producer circulates the pseudo code of the item
while(1) { // If the buffer is full, the producer is blocked wait(full_sem); // If another producer is releasing products, this producer is blocked wait(mutex_sem); Producer basis if Condition judgment produces the corresponding goods // Wake up blocked producers signal(mutex_sem); //Wake up waiting consumers signal(Corresponding consumers); }
Smoker's pseudo code
while(1) { // If no product is blocked by consumers wait(Semaphore of corresponding material); Smokers obtain materials and smoke // Wake up blocked producers signal(full_sem); }
4.2 complete code
ipc.h
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <sys/msg.h> #define BUFSZ 256 // Establish or obtain the prototype description of a set of functions of ipc int get_ipc_id(char *proc_file,key_t key); char *set_shm(key_t shm_key,int shm_num,int shm_flag); int set_msq(key_t msq_key,int msq_flag); int set_sem(key_t sem_key,int sem_val,int sem_flag); int down(int sem_id); int up(int sem_id); /*Community for signal lamp control*/ typedef union semuns { int val; } Sem_uns; /* Message structure */ typedef struct msgbuf { long mtype; char mtext[1]; } Msg_buf; // The production consumer shared buffer is its related variable key_t buff_key; int buff_num; char *buff_ptr; // Shared pointer of the producer to the product location key_t pput_key; int pput_num; int *pput_ptr; // The consumer takes the shared pointer of the product location key_t cget_key; int cget_num; int *cget_ptr; // Producer related semaphores //Semaphore with full buffer key_t full_key; //It is a mutually exclusive semaphore when the number of memories is guaranteed key_t mutex_key; int full_sem; int mutex_sem; // Consumer related semaphores //There's glue and grass key_t GlueGrass_key; //There's glue and paper key_t GluePaper_key; //There is paper and grass key_t PaperGrass_key; int GlueGrass_sem; int GluePaper_sem; int PaperGrass_sem; int sem_val; int sem_flg; int shm_flg;
ipc.c
#include "ipc.h" /* * get_ipc_id() Get the id number of IPC from the / proc/sysvipc / file system * pfile: The IPC files in the corresponding / proc/sysvipc / directory are * msg-Message queue, sem semaphore, shm shared memory * key: The key value corresponding to the id number of the IPC to be obtained */ int get_ipc_id(char *proc_file, key_t key) { FILE *pf; int i, j; char line[BUFSZ], colum[BUFSZ]; if((pf = fopen(proc_file, "r")) == NULL) { perror("Proc file not open"); exit(EXIT_FAILURE); } fgets(line, BUFSZ, pf); while(!feof(pf)) { i = j = 0; fgets(line, BUFSZ, pf); while(line[i] == ' ') i++; while(line[i] != ' ') colum[j++] = line[i++]; colum[j] = '\0'; if(atoi(colum) != key) continue; j = 0; while(line[i] == ' ') i++; while(line[i] !=' ') colum[j++] = line[i++]; colum[j] = '\0'; i = atoi(colum); fclose(pf); return i; } fclose(pf); return -1; } /* * down/up operation on signal lamp * semid:Semaphore array identifier * semnum:Semaphore array subscript * buf:Structure of operating signal lamp */ int down(int sem_id) { struct sembuf buf; buf.sem_op = -1; buf.sem_num = 0; buf.sem_flg = SEM_UNDO; if((semop(sem_id, &buf, 1)) < 0) { perror("down error "); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } int up(int sem_id) { struct sembuf buf; buf.sem_op = 1; buf.sem_num = 0; buf.sem_flg = SEM_UNDO; if((semop(sem_id, &buf, 1)) < 0) { perror("up error "); exit(EXIT_FAILURE); } return EXIT_SUCCESS; } /* * set_sem Function to establish a semaphore with n semaphores * If the establishment is successful, the identifier SEM of a semaphore array is returned_ id * Input parameters: * sem_key Key value of semaphore array * sem_val Number of semaphores in semaphore array * sem_flag Access rights of arrays such as signals */ int set_sem(key_t sem_key,int sem_val,int sem_flg) { int sem_id; Sem_uns sem_arg; // Tested by SEM_ Has the semaphore array identified by key been established if((sem_id = get_ipc_id("/proc/sysvipc/sem", sem_key)) < 0) { // semget creates a new signal lamp, and its label returns to sem_id if((sem_id = semget(sem_key, 1, sem_flg)) < 0) { perror("semaphore create error"); exit(EXIT_FAILURE); } // Set the initial value of the signal lamp sem_arg.val = sem_val; if(semctl(sem_id, 0, SETVAL, sem_arg) < 0) { perror("semaphore set error"); exit(EXIT_FAILURE); } } return sem_id; } /* * set_shm Function to create a shared memory area with n bytes * If the establishment is successful, a pointer SHM to the first address of the memory area is returned_ buf * Input parameters: * shm_key Key value of shared memory * shm_val Length of shared memory bytes * shm_flag Access to shared memory */ char* set_shm(key_t shm_key,int shm_num,int shm_flg) { int i, shm_id; char * shm_buf; // Test by SHM_ Whether the shared memory area identified by key has been established if((shm_id = get_ipc_id("/proc/sysvipc/shm", shm_key)) < 0) { // shmget creates a new one with the length of shm_num bytes of shared memory, and its label is returned to shm_id if((shm_id = shmget(shm_key,shm_num,shm_flg)) <0) { perror("shareMemory set error"); exit(EXIT_FAILURE); } // shmat will be controlled by SHM_ The shared memory identified by ID is attached to the pointer shm_buf if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0) { perror("get shareMemory error"); exit(EXIT_FAILURE); } for(i = 0; i < shm_num; i++) shm_buf[i] = 0; //Initial 0 } // shm_ The shared memory area identified by key has been established and will be used by SHM_ The shared memory identified by ID is attached to the pointer shm_buf if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0) { perror("get shareMemory error"); exit(EXIT_FAILURE); } return shm_buf; } /* * set_msq Function to establish a message queue * If the establishment is successful, an identifier MSQ of the message queue is returned_ id * Input parameters: * msq_key Key value of message queue * msq_flag Access rights of message queue */ int set_msq(key_t msq_key,int msq_flg) { int msq_id; //Test by MSQ_ Whether the message queue identified by key has been established if((msq_id = get_ipc_id("/proc/sysvipc/msg", msq_key)) < 0) { //msgget creates a new message queue and returns its label to msq_id if((msq_id = msgget(msq_key,msq_flg)) < 0) { perror("messageQueue set error"); exit(EXIT_FAILURE); } } return msq_id; }
producer.c
#include "ipc.h" int main(int argc, char *argv[]) { int rate; // You can specify the number of sleep seconds of a process in the first parameter of the command line to mediate the execution speed of the process if(argv[1] != NULL) rate = atoi(argv[1]); else rate = 3; // Not specified as 3 seconds // Variables used by shared memory buff_key = 1001; // The key value assigned to the buffer buff_num = 1; // Given buffer length pput_key = 1002; // The producer puts the key value of the product pointer pput_num = 1; // Number of pointers shm_flg = IPC_CREAT | 0644; // Shared memory read and write permissions // Get the shared memory used by the buffer, buff_ptr points to the first address of the buffer buff_ptr = (char*)set_shm(buff_key, buff_num, shm_flg); // Get the producer's product placement pointer pput_ptr pput_ptr = (int*)set_shm(pput_key, pput_num, shm_flg); // Variables used by semaphores full_key = 2001; mutex_key = 2002; GlueGrass_key = 2003; GluePaper_key = 2004; PaperGrass_key = 2005; sem_flg = IPC_CREAT | 0644; // The initial value of producer synchronization signal is set as the maximum available amount of buffer sem_val = buff_num; // Get the full synchronization light, and save the reference ID as full_sem full_sem = set_sem(full_key,sem_val,sem_flg); // The initial value of the synchronization signal lamp is set to 0 when there is no product available for the consumer sem_val = 0; // Get the consumer synchronization signal light and save the reference ID GlueGrass_sem GlueGrass_sem = set_sem(GlueGrass_key,sem_val,sem_flg); // Get the consumer synchronization signal light and save the reference ID in GluePaper_sem GluePaper_sem = set_sem(GluePaper_key,sem_val,sem_flg); // Get the consumer synchronization signal light and save the reference ID in PaperGrass_sem PaperGrass_sem = set_sem(PaperGrass_key,sem_val,sem_flg); // The initial value of producer mutually exclusive signal lamp is 1 sem_val = 1; // Get the producer mutually exclusive semaphore, and store the reference ID mutex_sem mutex_sem = set_sem(mutex_key,sem_val,sem_flg); //Array index of buffer int index = 0; // Loop execution simulates the continuous release of products by producers while(1) { int count = (index++) % 3; // If the buffer is full, the producer is blocked down(full_sem); // If another producer is releasing products, this producer is blocked down(mutex_sem); // Use the form of writing a material to simulate the producer to put the product, and report the process number, the characters put in and the storage location buff_ptr[*pput_ptr] = 'A'+ index; sleep(rate); if(count == 0) { printf("%d producer put: glue and grass to Buffer[%d]\n",getpid(),*pput_ptr); } else if(count == 1) { printf("%d producer put: glue and paper to Buffer[%d]\n",getpid(),*pput_ptr); } else if(count == 2) { printf("%d producer put: grass and paper to Buffer[%d]\n",getpid(),*pput_ptr); } // The storage position moves down circularly *pput_ptr = (*pput_ptr+1) % buff_num; // Wake up blocked producers up(mutex_sem); //Wake up the corresponding smoker if(count == 0) { up(GlueGrass_sem); } else if(count == 1) { up(GluePaper_sem); } else if(count == 2) { up(PaperGrass_sem); } } return EXIT_SUCCESS; }
consumer_glue.c
/* Smokers with glue, paper and tobacco */ #include "ipc.h" int main(int argc,char *argv[]) { int rate; // You can specify the number of sleep seconds of a process in the first parameter of the command line to mediate the execution speed of the process if(argv[1] != NULL) rate = atoi(argv[1]); else rate = 3; // Not specified as 3 seconds // Variables used by shared memory buff_key = 1001; // The key value assigned to the buffer buff_num = 1; // Given buffer length cget_key = 1003; // The consumer takes the key value of the product pointer cget_num = 1; // Number of pointers shm_flg = IPC_CREAT | 0644; //Shared memory read and write permissions // Get the shared memory used by the buffer, buff_ptr points to the first address of the buffer buff_ptr = (char *)set_shm(buff_key,buff_num,shm_flg); // Get consumer product pointer, cget_ptr points to index address cget_ptr = (int *)set_shm(cget_key,cget_num,shm_flg); // Variables used by semaphores full_key = 2001; mutex_key = 2002; GlueGrass_key = 2003; GluePaper_key = 2004; PaperGrass_key = 2005; sem_flg = IPC_CREAT | 0644; // Operation authority of signal lamp // The initial value of producer synchronization signal is set as the maximum available amount of buffer sem_val = buff_num; // Obtain the full semaphore and save it as full_sem full_sem = set_sem(full_key,sem_val,sem_flg); // The initial value of the synchronization signal lamp is set to 0 when there is no product available for the consumer sem_val = 0; // Get the consumer synchronization signal light and save the reference ID in PaperGrass_sem PaperGrass_sem = set_sem(PaperGrass_key,sem_val,sem_flg); // Circular execution simulates that consumers constantly take products while(1) { // If no product is blocked by consumers down(PaperGrass_sem); // Simulate the consumer to take the product in the form of reading one character, and report the process number, the obtained characters and the reading position sleep(rate); printf("%d glue smoker get paper and grass: %c from Buffer[%d]\n", getpid(), buff_ptr[*cget_ptr], *cget_ptr); // Read position cycle down *cget_ptr = (*cget_ptr+1) % buff_num; // Wake up blocked producers up(full_sem); } return EXIT_SUCCESS; }
consumer_paper.c
/* Smokers with paper, glue and tobacco */ #include "ipc.h" int main(int argc,char *argv[]) { int rate; // You can specify the number of sleep seconds of a process in the first parameter of the command line to mediate the execution speed of the process if(argv[1] != NULL) rate = atoi(argv[1]); else rate = 3; // Not specified as 3 seconds // Variables used by shared memory buff_key = 1001; // The key value assigned to the buffer buff_num = 1; // Given buffer length cget_key = 1003; // The consumer takes the key value of the product pointer cget_num = 1; // Number of pointers shm_flg = IPC_CREAT | 0644; //Shared memory read and write permissions // Get the shared memory used by the buffer, buff_ptr points to the first address of the buffer buff_ptr = (char *)set_shm(buff_key,buff_num,shm_flg); // Get consumer product pointer, cget_ptr points to index address cget_ptr = (int *)set_shm(cget_key,cget_num,shm_flg); // Variables used by semaphores full_key = 2001; mutex_key = 2002; GlueGrass_key = 2003; GluePaper_key = 2004; PaperGrass_key = 2005; sem_flg = IPC_CREAT | 0644; // Operation authority of signal lamp // The initial value of producer synchronization signal is set as the maximum available amount of buffer sem_val = buff_num; // Obtain the full semaphore and save it as full_sem full_sem = set_sem(full_key,sem_val,sem_flg); // The initial value of the synchronization signal lamp is set to 0 when there is no product available for the consumer sem_val = 0; // Get the consumer synchronization signal light and save the reference ID GlueGrass_sem GlueGrass_sem = set_sem(GlueGrass_key,sem_val,sem_flg); // Circular execution simulates that consumers constantly take products while(1) { // If no product is blocked by consumers down(GlueGrass_sem); // Simulate the consumer to take the product in the form of reading one character, and report the process number, the obtained characters and the reading position sleep(rate); printf("%d paper smoker get glue and grass: %c from Buffer[%d]\n", getpid(), buff_ptr[*cget_ptr], *cget_ptr); // Read position cycle down *cget_ptr = (*cget_ptr+1) % buff_num; // Wake up blocked producers up(full_sem); } return EXIT_SUCCESS; }
consumer_tobacco.c
/* Smokers with tobacco and lack of glue and paper */ #include "ipc.h" int main(int argc,char *argv[]) { int rate; // You can specify the number of sleep seconds of a process in the first parameter of the command line to mediate the execution speed of the process if(argv[1] != NULL) rate = atoi(argv[1]); else rate = 3; // Not specified as 3 seconds // Variables used by shared memory buff_key = 1001; // The key value assigned to the buffer buff_num = 1; // Given buffer length cget_key = 1003; // The consumer takes the key value of the product pointer cget_num = 1; // Number of pointers shm_flg = IPC_CREAT | 0644; //Shared memory read and write permissions // Get the shared memory used by the buffer, buff_ptr points to the first address of the buffer buff_ptr = (char *)set_shm(buff_key,buff_num,shm_flg); // Get consumer product pointer, cget_ptr points to index address cget_ptr = (int *)set_shm(cget_key,cget_num,shm_flg); // Variables used by semaphores full_key = 2001; mutex_key = 2002; GlueGrass_key = 2003; GluePaper_key = 2004; PaperGrass_key = 2005; sem_flg = IPC_CREAT | 0644; // Operation authority of signal lamp // The initial value of producer synchronization signal is set as the maximum available amount of buffer sem_val = buff_num; // Obtain the full semaphore and save it as full_sem full_sem = set_sem(full_key,sem_val,sem_flg); // The initial value of the synchronization signal lamp is set to 0 when there is no product available for the consumer sem_val = 0; // Get the consumer synchronization signal light and save the reference ID GlueGrass_sem GluePaper_sem = set_sem(GluePaper_key,sem_val,sem_flg); // Circular execution simulates that consumers constantly take products while(1) { // If no product is blocked by consumers down(GluePaper_sem); // Simulate the consumer to take the product in the form of reading one character, and report the process number, the obtained characters and the reading position sleep(rate); printf("%d grass smoker get glue and paper: %c from Buffer[%d]\n", getpid(), buff_ptr[*cget_ptr], *cget_ptr); // Read position cycle down *cget_ptr = (*cget_ptr+1) % buff_num; // Wake up blocked producers up(full_sem); } return EXIT_SUCCESS; }
makefile file
hdrs = ipc.h opts = -g -c p_src = producer.c ipc.c p_obj = producer.o ipc.o c_T_src = consumer_tobacco.c ipc.c c_T_obj = consumer_tobacco.o ipc.o c_P_src = consumer_paper.c ipc.c c_P_obj = consumer_paper.o ipc.o c_G_src = consumer_glue.c ipc.c c_G_obj = consumer_glue.o ipc.o all: producer consumer_tobacco consumer_paper consumer_glue producer: $(p_obj) gcc $(p_obj) -o producer producer.o: $(p_src) $(hdrs) gcc $(opts) $(p_src) consumer_tobacco: $(c_T_obj) gcc $(c_T_obj) -o consumer_tobacco consumer_tobacco.o: $(c_T_src) $(hdrs) consumer_paper: $(c_P_obj) gcc $(c_P_obj) -o consumer_paper consumer_paper.o: $(c_P_src) $(hdrs) gcc $(opts) $(c_P_src) -lrt consumer_glue: $(c_G_obj) gcc $(c_G_obj) -o consumer_glue consumer_glue.o: $(c_G_src) $(hdrs) gcc $(opts) $(c_G_src) -lrt clean: rm producer consumer_tobacco consumer_paper consumer_glue *.o
4.3 operation screenshot
5, Precautions
Due to different understanding of the experimental topic, some people have different understanding of this topic. Some people think that the length of the buffer is 2, and the producer puts materials into buffer[0] and buffer[1], while others think that the length of the buffer is 1, and the producer only puts two goods into buffer[0] at a time. I specially asked for the suggestion of the experimental teacher. The experimental teacher thought both schemes were OK. Here I choose the latter scheme, which is relatively simple. The former scheme is more complex, but the basic principles are the same