使用linux系统提供的信号量集和共享内存实现生产者和消费者问题

使用linux系统提供的信号量集和共享内存实现生产者和消费者问题

实验目的
了解和熟悉linux系统下的信号量集和共享内存。

实验任务
使用linux系统提供的信号量集和共享内存实现生产者和消费者问题。

实验要求
1.写两个程序,一个模拟生产者过程,一个模拟消费者过程;
2.创建一个共享内存模拟生产者-消费者问题中缓冲队列,该缓冲队列有N(例如N=10)个缓冲区,每个缓冲区的大小为1024B,每个生产者和消费者对缓冲区必须互斥访问;
3.由第一个生产者创建信号量集和共享内存,其他生产者和消费者可以使用该信号量集和共享内存;
4.生产者程序:生产者生产产品(即是从键盘输入长度小于1024B的字符)放入空的缓冲区;
5.消费者程序:消费者消费产品(即从满的缓冲区中取出内容在屏幕上打印出来),然后满的缓冲区变为空的缓冲区;
6.多次运行生产者程序和消费者进程,可以产生多个生产者进程和多个消费者进程,这些进程可以共享这些信号量和共享内存,实现生产者和消费者问题;
7.在生产者程序程序中,可以选择:
①生产产品;
②退出。退出进程,但信号量和共享内存仍然存在,其他生产者进程和消费者进程还可以继续使用;
③删除信号量和共享内存。显性删除信号量和共享内存,其他生产者进程和消费者进程都不能使用这些信号量和共享内存。
8.在消费者程序中,可以选择:
①消费产品;
②退出。退出进程,但信号量和共享内存仍然存在,其他生产者进程和消费者进程还可以继续使用;
③删除信号量和共享内存。显性删除信号量和共享内存,其他生产者进程和消费者进程都不能使用这些信号量和共享内存。

一、实验分析
生产者和消费者之间的关系:
(1)对缓冲区的访问是互斥的。
两者都会修改缓冲区,因此,一方修改缓冲区时,另一方不能修改,这就是互斥。
(2)一方的行为影响另一方。
缓冲区不空,才能消费,何时不空?生产了就不空;缓冲区满,就不能生产,何时不满?消费了就不满。这是同步关系。

要满足这两个要求,共需要三个信号量:
第一个信号量用于限制生产者必须在缓冲区不满时才能生产,是同步信号量(empty)
第二个信号量用于限制消费者必须在缓冲区有产品时才消费,是同步信号量(full)
第三个信号量用于限制生产者和消费者在访问缓冲区时必须互斥,是互斥信号量(mutex)

信号量集:
1.创建和访问一个信号量集
int semid = semget(key_t key, int nsems, int semflg);
返回值:正确返回信号量集的标识符,错误时返回-1。
key: 信号量集的标识(保持值相同,则不同进程打开同一个信号量集)
nsems:指定打开或者新创建的信号量集将包含的信号量的数目
semflg:
(1)只设置IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符
(2)设置IPC_CREAT|IPC_EXCL位,则创建一个新的信号量集,如果该key值的信号量已经存在,则返回错误信息。
如,创建一个只包含一个信号量的信号量集:
int semid = semget((key_t)SEM_KEY,1,IPC_CREAT|0666|IPC_EXCL);

2.对信号量的PV操作
int semop(int semid ,struct sembuf * sops ,unsigned nsops);
返回值:正确返回0,错误时返回-1
semid:是信号量集的标识符,由semget()得到
sops:指向一个sembuf结构数组,该数组的每一个元素对应一次信号量操作

struct sembuf {
	unsigned short sem_num;//semaphore index in array
							//标明它是信号量集的第几个元素,从0开始
	short sem_op;               /*semaphore operation*/ 
	short sem_flg;              /*operation flags,操作的执行模式*/
};

其中sembuf结构:
sem_op:对指定信号量采取的操作

sem_op<0相当于P操作,占有资源
sem_op>0相当于V操作,释放资源
sem_op=0进程睡眠直到信号量的值为0

nsops:进行操作信号量的个数,最常见设置此值等于1,只完成对一个信号量的操作

3.信号量集的控制函数
int semctl(int semid ,int semnum ,int cmd ,union semun arg);
返回值:正确时根据cmd的的不同返回值或0,错误时返回-1。
semid:是信号量集的标识符,由semget()得到
semnum:指定semid信号量集的第几个信号量,在撤销信号量集时,此参数可缺省。
cmd:指定操作类型。实验中使用:
SETVAL:指定semval域值为arg.val(指定信号的值为arg.val的值)
GETVAL:返回semnum指定的信号量的semval域值(得到指定信号的值)
IPC_RMID:删除指定信号量集。
如,撤销信号量集 semctl(semid ,IPC_RMID ,0)

③共享内存
1.共享存储是进程间通信的一种手段。共享内存并未提供同步机制,也就是说,
在一个服务进程结束对共享内存的写操作之前,并没有自动机制可以阻止另一个进程(客户进程)开始对它进行读取。共享内存必须自己考虑同步问题,通常使用信号量同步或互斥访问共享存储。
2.共享内存的生命周期随内核,即所有访问共享内存区域对象的进程都已经正常结束,共享内存区域对象仍然在内核中存在(除非显式删除共享内存区域对象)
3.本实验中,使用共享内存代表缓冲区,互斥信号量控制对缓冲区的访问。共享存储区的原理是将进程的地址空间映射到一个共享存储段。
与共享内存有关的所有函数共用头文件:

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

1.创建共享内存或获得一块共享内存区
int shmid = shmget(key_t key, size_t size, int shmflg);
返回值:成功返回共享内存的描述符,出错返回-1
key:长整型(唯一、非零),系统建立IPC通讯 ( 消息队列、 信号量和 共享内存) 时必须指定一个id值。通常情况下,该id值通过ftok()得到,由内核变成标识符,要想让两个进程看到同一个信号集,只需设置key值不变就可以。
size:指定共享内存的大小
shmflg:是一组标志
(1)只设置IPC_CREAT标志位,则创建一个共享内存段,如果该共享内存段已经存在,则返回其标识符
(2)设置IPC_CREAT|IPC_EXCL标志位,则可以创建一个新的、唯一的共享内存,如果共享内存已存在,返回一个错误。

2.挂接操作(将一共享存储区附接到进程的虚地址空间)
void * viraddr = shmat(int shm_id, const void *shm_addr, int shmflg);
shm_id:由shmget()返回的共享内存标识
shm_addr:指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
shm_flg:是一组标志位,通常为0

3.操作共享内存(设置共享存储区的有关的参数)
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
shm_id:由shmget()返回的共享内存标识
cmd:是要采取的操作,本实验中使用IPC_RMID(删除共享内存段)
buf:指向共享内存模式和访问权限的结构,本实验中设置为0
如,释放共享内存shmctl(shmid,IPC_RMID,0);

4.分离操作(把共享的内存区域和它自己的地址空间分离开)
int shmdt(const void *shmaddr);
shmaddr:调用shmat时的返回值
注意,该分离操作不从系统中删除标识符和其数据结构,要显示调用shmctl(带命令IPC_RMID)才能删除共享内存区

二、实验过程与结果
①生产者过程原型:

void producer(){
	while(1){
		item = produce_item();	//生产新的数据项
		wait(empty);
		wait(mutex);			//进入临界区
		Buffer[in] = item;		//新生产的数据项放入缓冲区
		in = (in + 1)%N;				
		signal(mutex);			//离开临界区
		signal(full);				//增加已用缓冲区的数目
	}
}

消费者过程原型:

void consumer(){
	while(1){
		wait(full);			
		wait(mutex);			//进入临界区
		item = Buffer(out);		//新生产的数据项放入缓冲区
		out = (out + 1)%N;			
		signal(mutex);			//离开临界区
		signal(empty);			//增加空闲缓冲区的数目
		consume_item(item);	//处理取出的数据项
	}
}

②程序代码
1.生产者过程(Producer.c)

//Producer.c

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/shm.h>

#include <sys/ipc.h>
#include <errno.h>

#define BUF_SIZ 1024  //每个缓冲区的大小
#define N 10		//有N(例如N=10)个缓冲区

#define SEM_KEY_1 1
#define SEM_KEY_2 2
#define SEM_KEY_3 3
//#define SHM_KEY 4

union semun {//共同体类型semun
	int val;//使用的值
	struct semid_ds *buf;   //使用的缓存区,struct semid_ds信号量集的数据结构,在头文件 <sys/sem.h>
	unsigned short * array;//使用的数组
}arg;//该联合体没有定义在任何系统头文件中,因此得用户自己声明

int emptyid;//同步信号量(empty),限制生产者必须在缓冲区空时才生产
int fullid; //同步信号量(full),限制消费者必须在缓冲区有产品时才消费

int mutexid;//互斥信号量(mutex),限制生产者和消费者在访问缓冲区i时必须互斥

//共享内存区结构
struct shared_use_st {
	int Index[N]; //为0,表示对应的缓冲区i未被生产者使用,可生产但不可消费;为1,表示对应的缓冲区i已被生产者使用,不可分配但可消费
	char Buffer[N][BUF_SIZ];    //该缓冲队列有N个字符串缓冲区,每个缓冲区的大小为BUF_SIZ
};


int main() {
	/*****申请只有一个信号量的信号量集*****/
	emptyid = semget((key_t)SEM_KEY_1, 1, IPC_CREAT | 0666 | IPC_EXCL);//创建和访问一个信号量集,第二个参数为信号量的个数,
	fullid = semget((key_t)SEM_KEY_2, 1, IPC_CREAT | 0666 | IPC_EXCL);//创建一个只包含一个信号量的信号量集,即蜕化为一般的记录型信号量或互斥信号量 
	// IPC_CREAT|IPC_EXCL 创建一个新的信号量集,如果该值的信号量已经存在,则返回错误信息,(0666为IPC对象存取权限)
	mutexid = semget((key_t)SEM_KEY_3, 1, IPC_CREAT | 0666 | IPC_EXCL);//申请互斥信号量if (emptyid == -1) {//错误时返回-1if (errno == EEXIST) {//打开已有的信号量
​			emptyid = semget((key_t)SEM_KEY_1, 1, IPC_CREAT | 0666);//打开已有的信号量
​			fullid = semget((key_t)SEM_KEY_2, 1, IPC_CREAT | 0666);//只设置IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符
​			mutexid = semget((key_t)SEM_KEY_3, 1, IPC_CREAT | 0666);}}else {//需要赋初值/*分别对每个信号量赋初值*/
​		arg.val = N;//同步信号量empty的初值为Nif (semctl(emptyid, 0, SETVAL, arg) == -1)perror("semctl setval error");//SETVAL指定信号量的初值为arg.val
​		arg.val = 0;//同步信号量full的初值为0if (semctl(fullid, 0, SETVAL, arg) == -1)perror("semctl setval error");//SETVAL指定信号量的初值为arg.val
​		arg.val = 1;//互斥信号量mutex的初值为1if (semctl(mutexid, 0, SETVAL, arg) == -1)perror("semctl setval error");//SETVAL指定信号量的初值为arg.val}/*定义PV操作*/struct sembuf P, V;
​	P.sem_num = 0;//信号量集的第0个元素
​	P.sem_op = -1;//<0相当于P操作,占有资源
​	P.sem_flg = SEM_UNDO;//指明内核为信号量操作保留恢复值
​	V.sem_num = 0;//信号量集的第0个元素
​	V.sem_op = 1;//>0相当于V操作,释放资源
​	V.sem_flg = SEM_UNDO;//指明内核为信号量操作保留恢复值/*****申请或访问共享内存空间*****/int shmid;//共享内存标识符     
​	shmid = shmget((key_t)1121, sizeof(struct shared_use_st), 0666 | IPC_CREAT | IPC_EXCL);//获得或创建一个共享内存标识符,要想让两个进程看到同一个信号集,只需设置第一个值不变就可以//IPC_CREAT|IPC_EXCL创建一个新的、唯一的共享内存,如果共享内存已存在,返回一个错误 if (shmid == -1) {//获得共享内存空间的标识符if (errno == EEXIST) {//共享内存已存在
​			shmid = shmget((key_t)1121, sizeof(struct shared_use_st), 0666 | IPC_CREAT);}else return -1;}/*将共享内存连接到当前进程的地址空间*/void * shm = NULL;//分配的共享内存的原始首地址
​	shm = shmat(shmid, (void*)0, 0); //返回共享内存的原始首地址if (shm == (void*)-1)exit(EXIT_FAILURE);//失败printf("Memory attached at %ld\n", (intptr_t)shm);struct shared_use_st * viraddr = NULL;//连接到该进程的虚地址空间,即应指向shm
​	viraddr = (struct shared_use_st*)shm;//设置共享内存,viraddr连接到该进程的虚地址空间if (semctl(emptyid, 0, GETVAL) == N) {//empty==N,即缓冲区都可分配printf("初始化共享内存\n");for (int i = 0; i < N; i++)viraddr->Index[i] = 0;}char buffer[BUF_SIZ];        //用于保存输入的文本int i = 0;while (1) {for (i = 0; i < N && viraddr->Index[i] == 1; i++);//找到可被生产者使用的缓冲区Buffer[i] //Index为1表示缓冲区i被消费者占用if (i == N) {//当N个缓冲区都被消费者占用时输出“waiting...”sleep(1);        //sleep一段时间,再次进入循环printf("Waiting...\n");}else {//缓冲区Buffer[i]未被消费者占用semop(emptyid, &P, 1);//最后一个参数值为1,只完成对一个信号量的操作  wait(empty)semop(mutexid, &P, 1);//最后一个参数值为1,只完成对一个信号量的操作  wait(mutex)for (i = 0; i < N && viraddr->Index[i] == 1; i++);//找到可被生产者使用的缓冲区Buffer[i] //Index为1表示缓冲区i被消费者占用 //puts("Enter your text:");fgets(buffer, BUF_SIZ, stdin);//读取stdin字符流最多BUF_SIZ个,并存在buffer数组中strcpy(viraddr->Buffer[i%N], buffer);//读取的字符串存入缓冲区viraddr->Buffer[i]中
​			viraddr->Index[i%N] = 1;//表示该缓冲区被生产者使用了semop(fullid, &V, 1);//signal(full)semop(mutexid, &V, 1);//signal(mutex)if (strncmp(buffer, "end", 3) == 0) { sleep(1); break; }	//输入end,该生产者结束生产	}}//结束循环/*将共享内存从当前进程中分离*/int choice;printf("请选择1.退出 2.删除信号量和共享内存:");scanf("%d", &choice);if (shmdt(viraddr) == -1)exit(EXIT_FAILURE);//分离链接的共享内存if (choice == 2) {semctl(emptyid, IPC_RMID, 0);//撤销信号量集semctl(fullid, IPC_RMID, 0);semctl(mutexid, IPC_RMID, 0);if (shmctl(shmid, IPC_RMID, 0) == -1)exit(EXIT_FAILURE);//显示调用shmctl(带命令IPC_RMID)才能删除共享内存printf("已删除信号量和共享内存!\n");}else printf("已退出\n");exit(EXIT_SUCCESS);
}

2.消费者过程(Comsumer.c)

//Comsumer.c

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/sem.h>
#include<sys/shm.h>

#include <sys/ipc.h>
#include <errno.h>

#define BUF_SIZ 1024  //每个缓冲区的大小
#define N 10	//有N(例如N=10)个缓冲区

#define SEM_KEY_1 1
#define SEM_KEY_2 2
#define SEM_KEY_3 3
//#define SHM_KEY 4

union semun {//共同体类型semun
	int val;//使用的值
	struct semid_ds *buf;   //使用的缓存区,struct semid_ds信号量集的数据结构,在头文件 <sys/sem.h>
	unsigned short * array;//使用的数组
}arg;//该联合体没有定义在任何系统头文件中,因此得用户自己声明

int emptyid;//同步信号量(empty),限制生产者必须在缓冲区空时才生产
int fullid; //同步信号量(full),限制消费者必须在缓冲区有产品时才消费

int mutexid;//互斥信号量(mutex),限制生产者和消费者在访问缓冲区i时必须互斥

//共享内存区结构
struct shared_use_st {
	int Index[N]; //为0,表示对应的缓冲区i未被生产者使用,可生产但不可消费;为1,表示对应的缓冲区i已被生产者使用,不可分配但可消费
	char Buffer[N][BUF_SIZ];    //该缓冲队列有N个字符串缓冲区,每个缓冲区的大小为BUF_SIZ
};


int main() {
	/*****访问只有一个信号量的信号量集*****/
	emptyid = semget((key_t)SEM_KEY_1, 1, IPC_CREAT | 0666 | IPC_EXCL);//访问一个信号量集,第二个参数为信号量的个数
	//IPC_CREAT|IPC_EXCL 创建一个新的信号量集,如果该的信号量已经存在,则返回错误信息
	if (emptyid == -1) {//错误时返回-1
		if (errno == EEXIST) {//打开已有的信号量
			emptyid = semget((key_t)SEM_KEY_1, 1, IPC_CREAT | 0666);//打开已有的信号量
			fullid = semget((key_t)SEM_KEY_2, 1, IPC_CREAT | 0666);//只设置IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符
			mutexid = semget((key_t)SEM_KEY_3, 1, IPC_CREAT | 0666);
		}
	}/*定义PV操作*/struct sembuf P, V;
​	P.sem_num = 0;//信号量集的第0个元素
​	P.sem_op = -1;//<0相当于P操作,占有资源
​	P.sem_flg = SEM_UNDO;//指明内核为信号量操作保留恢复值
​	V.sem_num = 0;//信号量集的第0个元素
​	V.sem_op = 1;//>0相当于V操作,释放资源
​	V.sem_flg = SEM_UNDO;//指明内核为信号量操作保留恢复值/*****访问共享内存空间*****/int shmid;//共享内存标识符 
​	shmid = shmget((key_t)1121, sizeof(struct shared_use_st), 0666 | IPC_CREAT);//共享内存已存在,获得共享内存标识符/*将共享内存连接到当前进程的地址空间*/void * shm = NULL;//分配的共享内存的原始首地址
​	shm = shmat(shmid, (void*)0, 0); //返回共享内存的原始首地址if (shm == (void*)-1)exit(EXIT_FAILURE);//失败printf("Memory attached at %ld\n", (intptr_t)shm);struct shared_use_st * viraddr = NULL;//连接到该进程的虚地址空间,即应指向shm 
​	viraddr = (struct shared_use_st*)shm;//设置共享内存,viraddr连接到该进程的虚地址空间char buffer[BUF_SIZ];        //用于保存输入的文本int i = 0;while (1) {for (i = 0; i < N && viraddr->Index[i] == 0; i++);//找到可被消费者使用的缓冲区Buffer[i],Index为0表示缓冲区i被生产者占用if (i == N) {//当N个缓冲区都被生产者占用时输出“waiting...”sleep(1);        //sleep一段时间,再次进入循环printf("Waiting...\n");}else {semop(fullid, &P, 1);//最后一个参数值为1,只完成对一个信号量的操作  wait(full)semop(mutexid, &P, 1);//最后一个参数值为1,只完成对一个信号量的操作  wait(mutex)for (i = 0; i < N && viraddr->Index[i] == 0; i++);//找到可被消费者使用的缓冲区Buffer[i],Index为0表示缓冲区i被生产者占用//printf("Your message is:%s\n", viraddr->Buffer[i%N]);
​			viraddr->Index[i%N] = 0;//表示该缓冲区被消费者使用了semop(emptyid, &V, 1);//signal(empty)semop(mutexid, &V, 1);//signal(mutex)if (strncmp(viraddr->Buffer[i%N], "end", 3) == 0)break;//输入end,该消费者结束生产	}}//结束循环/*将共享内存从当前进程中分离*/int choice;printf("请选择1.退出 2.删除信号量和共享内存:");scanf("%d", &choice);if (shmdt(viraddr) == -1)exit(EXIT_FAILURE);//分离链接的共享内存if (choice == 2) {semctl(emptyid, IPC_RMID, 0);//撤销信号量集semctl(fullid, IPC_RMID, 0);semctl(mutexid, IPC_RMID, 0);if (shmctl(shmid, IPC_RMID, 0) == -1)exit(EXIT_FAILURE);//显示调用shmctl(带命令IPC_RMID)才能删除共享内存printf("已删除信号量和共享内存!\n");}else printf("已退出\n");exit(EXIT_SUCCESS);
}
三、 实验小结

计算机系统中,把并发进程的同步和互斥问题一般化,可以得到一个抽象的一般模型,即生产者-消费者问题。把系统中使用某一类资源的进程称为消费者,而把释放同类资源的进程称为该资源的生产者。

把一个长度为n的有界缓冲区(n>0)与一群生产者 P1,P2…Pm和一群消费者进程C1,C2…Cp联系起来。
在这里插入图片描述
信号量的设置:
Mutex=1 临界资源
Empty=n 空缓冲区的个数
Full=0 满缓冲区的个数,即可供消费的产品数量

进程通信中的共享存储区:
在存储器中划出了一块共享存储区,各生产者消费者进程可通过对共享存储区的读写来交换数据。
进程在通信前,先向系统申请获得共享存储区的描述符返回给申请者,然后,由申请者把获得的共享存储区连接到本进程上,以后就可像读、写普通存储器一样的读、写该共享存储区了。
共享内存并未提供同步机制,也就是说,在一个服务进程结束对共享内存的写操作之前,并没有自动机制可以阻止另一个进程(客户进程)开始对它进行读取。共享内存必须自己考虑同步问题,通常使用信号量同步或互斥访问共享存储。

  • 7
    点赞
  • 63
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux共享内存是一种进程间通信的方式,也可以用来解决生产者-消费者问题。下面是一个基本的共享内存实现生产者-消费者问题的例子: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> #include <sys/shm.h> #include <semaphore.h> #define SIZE 10 // 缓冲区大小 // 共享内存结构体 typedef struct { char buf[SIZE][256]; // 缓冲区 int head; // 缓冲区头指针 int tail; // 缓冲区尾指针 } shm_struct; // 信号量 sem_t *sem_mutex; // 互斥信号量,用来保证对缓冲区的互斥访问 sem_t *sem_empty; // 空缓冲区信号量,用来表示可用的空缓冲区数量 sem_t *sem_full; // 满缓冲区信号量,用来表示已经存储的数据量 // 共享内存ID和指针 int shmid; shm_struct *shm_ptr; // 生产者线程 void *producer(void *arg) { int i = 0; char *str = (char *)arg; while (1) { sem_wait(sem_empty); // 等待空缓冲区 sem_wait(sem_mutex); // 互斥访问缓冲区 sprintf(shm_ptr->buf[shm_ptr->tail], "%s %d", str, i++); shm_ptr->tail = (shm_ptr->tail + 1) % SIZE; // 缓冲区指针后移 sem_post(sem_mutex); // 释放互斥信号量 sem_post(sem_full); // 释放满缓冲区信号量 sleep(rand() % 2 + 1); // 随机休眠一段时间 } pthread_exit(NULL); } // 消费者线程 void *consumer(void *arg) { int i = 0; while (1) { sem_wait(sem_full); // 等待满缓冲区 sem_wait(sem_mutex); // 互斥访问缓冲区 printf("consumer[%d]: %s\n", i++, shm_ptr->buf[shm_ptr->head]); shm_ptr->head = (shm_ptr->head + 1) % SIZE; // 缓冲区指针后移 sem_post(sem_mutex); // 释放互斥信号量 sem_post(sem_empty); // 释放空缓冲区信号量 sleep(rand() % 2 + 1); // 随机休眠一段时间 } pthread_exit(NULL); } int main() { // 初始化共享内存 shmid = shmget(IPC_PRIVATE, sizeof(shm_struct), 0666 | IPC_CREAT); if (shmid < 0) { perror("shmget"); exit(1); } shm_ptr = (shm_struct *)shmat(shmid, NULL, 0); if (shm_ptr == (void *)-1) { perror("shmat"); exit(1); } shm_ptr->head = 0; shm_ptr->tail = 0; // 初始化信号量 sem_mutex = sem_open("/sem_mutex", O_CREAT, 0666, 1); sem_empty = sem_open("/sem_empty", O_CREAT, 0666, SIZE); sem_full = sem_open("/sem_full", O_CREAT, 0666, 0); // 创建生产者线程和消费者线程 pthread_t tid_producer, tid_consumer; pthread_create(&tid_producer, NULL, producer, (void *)"producer"); pthread_create(&tid_consumer, NULL, consumer, NULL); // 等待线程结束 pthread_join(tid_producer, NULL); pthread_join(tid_consumer, NULL); // 删除信号量共享内存 sem_unlink("/sem_mutex"); sem_unlink("/sem_empty"); sem_unlink("/sem_full"); shmctl(shmid, IPC_RMID, NULL); return 0; } ``` 该程序,定义了一个大小为10的缓冲区结构体`shm_struct`,其包含了缓冲区`buf`和头尾指针`head`和`tail`。同时,定义了三个信号量`sem_mutex`、`sem_empty`和`sem_full`,分别用来表示互斥访问缓冲区、可用的空缓冲区数量和已经存储的数据量。 生产者线程,不断等待空缓冲区和互斥访问缓冲区信号量,然后向缓冲区写入数据,并将缓冲区指针后移。最后释放互斥信号量和满缓冲区信号量,并随机休眠一段时间。 消费者线程,不断等待满缓冲区和互斥访问缓冲区信号量,然后从缓冲区读取数据,并将缓冲区指针后移。最后释放互斥信号量和空缓冲区信号量,并随机休眠一段时间。 在`main`函数,首先初始化共享内存信号量,然后创建生产者线程和消费者线程。最后等待线程结束,删除信号量共享内存

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值