使用信号量实现有限缓冲区的生产者和消费者问题(使用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下运行)的主要内容,如果未能解决你的问题,请参考以下文章

经典进程同步问题

在经典生产者消费者问题中,三个信号量可以设置为更少或更多吗

进程经典问题总结

进程经典问题总结

操作系统——2.2-3经典进程的同步问题

用c语言或c++编写编程实现生产者消费者或读写者的同步问题