使用信号量实现有限缓冲区的生产者和消费者问题(使用fork(),semget()等函数,能在GCC下运行)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用信号量实现有限缓冲区的生产者和消费者问题(使用fork(),semget()等函数,能在GCC下运行)相关的知识,希望对你有一定的参考价值。
看我下面的代码, 父进程是消费者,子进程是生产者。REPEATS 决定总共生产的次数 (可以自己修改)
CONSUMER_SPEED 决定消费的速度 (越大越慢,可以自己修改)
PRODUCER_SPEED 决定生产的速度 (越大越慢,可以自己修改)
我的例子里,生产者生产一个随机数。另外消费速度比生产速度慢,所以可以看到输出中,+++ (生产者) 开头的出现的比--- (消费者)多,当生产者结束后,就只有 --- 打印了。
对这个程序由什么问题,可以baidu hi我。在linux/unix下用 gcc 编译。
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
#define REPEATS (10) /* count of production/consumption */
#define MAX_BUFFER_SIZE (8)
typedef struct
int bottom;
int top;
int data[MAX_BUFFER_SIZE];
STRUCT_BUFFER;
STRUCT_BUFFER * pBuffer = NULL;
/* Define speed of consumer/producer, change them as u like */
#define PRODUCER_SPEED (1) /* 1/sec */
#define CONSUMER_SPEED (2) /* 1/2sec */
int sem_consume; /* consumer sem */
int sem_produce; /* producer sem */
int shm_buffer; /* shared buffer */
#define FLAG (IPC_CREAT | S_IRWXU)
/* Init semphores & shared buffer */
void init()
union semun
int val;
struct semid_ds *buf;
unsigned short *array;
arg;
shm_buffer = shmget(0x1111, sizeof(STRUCT_BUFFER), FLAG);
pBuffer = shmat(shm_buffer, 0, 0);
memset(pBuffer, 0, sizeof(STRUCT_BUFFER));
sem_consume = semget(0x2222, 1, FLAG);
arg.val = 0;
if (semctl(sem_consume, 0, SETVAL, arg) < 0)
perror("Consumer");
exit(1);
sem_produce = semget(0x3333, 1, FLAG);
arg.val = MAX_BUFFER_SIZE;
if (semctl(sem_produce, 0, SETVAL, arg) < 0)
perror("Producer");
exit(1);
/* destroy semphores & shared buffer */
void deinit()
shmctl(shm_buffer, IPC_RMID, NULL);
semctl(sem_consume, 0, IPC_RMID);
semctl(sem_produce, 0, IPC_RMID);
int main()
int pid, i;
struct sembuf sbuf;
init();
printf("Start fork...\n");
pid = fork();
if (pid > 0)
/* parent process, consumer */
for (i = 0; i < REPEATS; i++)
/* Try decrementing 1 from consumer */
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=0;
semop(sem_consume, &sbuf, 1);
/* OK */
printf("Consumer get %6d\n", pBuffer->data[pBuffer->bottom]);
pBuffer->bottom = (pBuffer->bottom+1)%MAX_BUFFER_SIZE;
/* Try incrementing 1 to producer */
sbuf.sem_op = 1;
semop(sem_produce, &sbuf, 1);
sleep(CONSUMER_SPEED);
wait(0);
shmdt(pBuffer);
else if (pid == 0)
srand(time(NULL));
/* child process, producer */
for (i = 0; i < REPEATS; i++)
/* Try decrementing 1 from producer */
sbuf.sem_num=0;
sbuf.sem_op=-1;
sbuf.sem_flg=0;
semop(sem_produce, &sbuf, 1);
/* OK */
pBuffer->data[pBuffer->top] = (rand()%1000)*1000 + i + 1;
printf("Producer put %6d\n", pBuffer->data[pBuffer->top]);
pBuffer->top = (pBuffer->top+1)%MAX_BUFFER_SIZE;
/* Try incrementing 1 to consumer */
sbuf.sem_op = 1;
semop(sem_consume, &sbuf, 1);
sleep(PRODUCER_SPEED);
shmdt(pBuffer);
exit(0);
deinit();
return 0;
参考技术A 写这个不是很难的。
有什么不懂得可以问我,我尽我所能帮你,账号就是QQ,我是计算机专业的。
操作系统——2.2-3经典进程的同步问题
1.生产者-消费者问题
系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。
- 生产者、消费者共享一个初始为空、大小为n的缓冲区,各进程互斥访问
- 缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待
- 缓冲区不空时,消费者才能从中取出产品,否则必须等待
semaphore mutex = 1;//互斥信号量,实现对缓冲区的互斥访问
semaphore empty = n;//同步信号量,表示空闲缓冲区的数量
semaphore full = 0; //同步信号量,表示产品的数量,即非缓冲区的数量
producer(){
while(1){
生产一个产品;
P(empty);//消耗一个空闲缓冲区
P(mutex);
把产品放入缓冲区;
V(mutex);
V(full);//增加一个产品
}
}
consumer(){
while(1){
P(full);//消耗一个产品
P(mutex);
从缓冲区取出一个产品;
V(mutex);
V(empty);//增加一个空闲缓冲区
使用产品;
}
}
2.哲学家进餐问题
一张圆桌上坐着5名哲学家,每两个哲学家之间的桌上摆一根筷子,桌子的中间是一碗米饭。哲学家们倾注毕生的精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时, 才试图拿起左、右两根筷子(一根一根地拿起)。如果筷子已在他人手上,则需等待。饥饿的哲学家只有同时拿起两根筷子才可以开始进餐,当进餐完毕后,放下筷子继续思考。
(主要是解决死锁现象的发生)
有三种方案
//1.对哲学家施加限制(如最多只有4个哲学家可以同时进餐,那么至少可以保证一个哲学家可以同时拿到左右两支筷子
semaphore chopstick[5] = {1,1,1,1,1};
int num = 4;
Pi(){
P(chopstick[i]);
P(chopstick[(i+1)%5]);
吃饭;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
思考;
}
//2.要求奇数号哲学家先拿左边的筷子,然后再拿右边的筷子
// 而偶数号哲学家先拿右边的筷子,然后再拿左边的筷子
semaphore chopstick[5] = {1,1,1,1,1};
Pi(){
if(i%2==1){
P(chopstick[i]);
P(chopstick[(i+1)%5]);
}
else{
P(chopstick[(i+1)%5]);
P(chopstick[i]);
}
吃饭;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
思考;
}
//3.仅当一个哲学家可以同时拿起两支筷子时,才允许他拿起筷子
//(1)使用AND信号量集
semaphore chopstick[5] = {1,1,1,1,1};
Pi(){
P(chopstick[i],chopstick[(i+1)%5]);
吃饭;
V(chopstick[i],chopstick[(i+1)%5]);
思考;
}
//(2)使用互斥信号量
semaphore chopstick[5] = {1,1,1,1,1};
semaphore mutex = 1;
Pi(){
P(mutex);
P(chopstick[i]);
P(chopstick[(i+1)%5]);
V(mutex);
吃饭;
P(chopstick[i]);
P(chopstick[(i+1)%5]);
}
3.读者-写者问题
有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时没有影响,但是某个写进程和其他进程(读或写)同时访问则可能导致数据不一致的错误。
- 允许多个读者可以同时对文件执行读操作
- 只允许一个写者往文件中写信息
- 任一写者在完成写操作之前不允许其他读者或写者工作
- 写者执行写操作前,应让已有的读者和写者全部退出
semaphore rwmutex = 1;//保证写操作和读操作的互斥
semaphore rmutex = 1;//防止读操作之间发生阻塞
int rcount = 0;//记录读进程的数量
writer(){
P(rwmutex);
写操作;
V(rwmutex);
}
reader(){
P(rmutex);
if(count == 0)
P(rwmutex);
count++;
V(rmutex);
读操作;
P(rmutex);
count--;
if(count == 0)
V(rwmutex);
V(rmutex);
}
读者-写者问题,读者优先需要注意:只要有读进程还在读,写进程就要一直阻塞等待,可能“饿死”
以上是关于使用信号量实现有限缓冲区的生产者和消费者问题(使用fork(),semget()等函数,能在GCC下运行)的主要内容,如果未能解决你的问题,请参考以下文章