Operating system experiment 4 of Software College of Shandong University -- Process Synchronization Experiment

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

  1. 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.
  2. 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
  3. 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

Keywords: Linux Ubuntu Operating System

Added by deadonarrival on Thu, 17 Feb 2022 22:10:48 +0200