使用多线程/进程和System V信号量解决生产者消费者问题:有一个长度为N的缓冲池(共享内存)被生产者和消费者共同使用。只要缓冲池未满,生产者就可以将消息送入缓冲池;只要缓冲池不空,消费者便可从缓冲池中取走一
时间: 2024-05-13 15:20:07 浏览: 107
信号量来解决操作系统的消费者与生产者问题.rar_信号量_生产者 消费者_进程
条消息。如果缓冲池已满,生产者必须等待,直到缓冲池中有可用空间;如果缓冲池为空,消费者必须等待,直到缓冲池中有消息可取。
使用多线程/进程和System V信号量可以很方便地解决这个问题。下面是一个基于Linux系统的C语言实现示例:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#define N 10 // 缓冲区大小
#define PRO_NUM 3 // 生产者数量
#define CON_NUM 2 // 消费者数量
int buffer[N]; // 缓冲区
int semid; // 信号量ID
int pmutex, cmutex; // 生产者、消费者互斥信号量
int pempty, cempty; // 生产者、消费者等待信号量
void P(int semid, int index) {
struct sembuf sem;
sem.sem_num = index;
sem.sem_op = -1;
sem.sem_flg = 0;
semop(semid, &sem, 1);
}
void V(int semid, int index) {
struct sembuf sem;
sem.sem_num = index;
sem.sem_op = 1;
sem.sem_flg = 0;
semop(semid, &sem, 1);
}
void *producer(void *arg) {
int i = *(int *)arg;
while (1) {
P(semid, pempty);
P(semid, pmutex);
// 生产者生产一个随机数
int item = rand() % 100;
buffer[i] = item;
printf("Producer %d produces item %d at buffer[%d]\n", i, item, i);
V(semid, pmutex);
V(semid, cempty);
sleep(rand() % 3); // 睡眠一段时间
}
}
void *consumer(void *arg) {
int i = *(int *)arg;
while (1) {
P(semid, cempty);
P(semid, cmutex);
// 消费者消费一个缓冲区中的随机数
int item = buffer[i];
buffer[i] = -1;
printf("Consumer %d consumes item %d at buffer[%d]\n", i, item, i);
V(semid, cmutex);
V(semid, pempty);
sleep(rand() % 3); // 睡眠一段时间
}
}
int main() {
// 创建信号量
semid = semget(IPC_PRIVATE, 4, IPC_CREAT | 0666);
if (semid < 0) {
perror("semget error");
exit(1);
}
// 初始化信号量
semctl(semid, 0, SETVAL, 1); // 生产者互斥信号量
semctl(semid, 1, SETVAL, 1); // 消费者互斥信号量
semctl(semid, 2, SETVAL, N); // 空闲缓冲区数量
semctl(semid, 3, SETVAL, 0); // 已使用缓冲区数量
// 创建线程
pthread_t pro[PRO_NUM], con[CON_NUM];
int i, index[PRO_NUM + CON_NUM];
for (i = 0; i < PRO_NUM; i++) {
index[i] = i;
pthread_create(&pro[i], NULL, producer, &index[i]);
}
for (i = 0; i < CON_NUM; i++) {
index[PRO_NUM + i] = i;
pthread_create(&con[i], NULL, consumer, &index[PRO_NUM + i]);
}
// 等待线程退出
for (i = 0; i < PRO_NUM; i++) {
pthread_join(pro[i], NULL);
}
for (i = 0; i < CON_NUM; i++) {
pthread_join(con[i], NULL);
}
// 删除信号量
semctl(semid, 0, IPC_RMID, 0);
return 0;
}
```
以上代码中,P和V函数分别用于对信号量进行P操作和V操作。每个生产者线程在生产一个随机数后,需要先获取空闲缓冲区数量的信号量pempty和生产者互斥信号量pmutex,然后将随机数存入缓冲区,并释放生产者互斥信号量pmutex和已使用缓冲区数量的信号量cempty。每个消费者线程在消费一个缓冲区中的随机数后,需要先获取已使用缓冲区数量的信号量cempty和消费者互斥信号量cmutex,然后将缓冲区中的随机数取出,释放消费者互斥信号量cmutex和空闲缓冲区数量的信号量pempty。同时,每个线程在生产或消费一个随机数后还会睡眠一段随机的时间,以模拟真实的生产消费过程。
在主函数中,我们首先创建了一个包含4个信号量的信号量集,分别表示生产者互斥信号量、消费者互斥信号量、空闲缓冲区数量和已使用缓冲区数量。然后创建了多个生产者线程和消费者线程,等待它们退出后删除信号量集。
这里使用了System V信号量,也可以使用POSIX信号量来实现。不过POSIX信号量需要使用sem_init、sem_wait、sem_post等函数,使用起来略有不同。
阅读全文