使用多线程/进程和System V信号量解决生产者消费者问题:有一个长度为N的缓冲池(共享内存)被生产者和消费者共同使用。只要缓冲池未满,生产者就可以将消息送入缓冲池;只要缓冲池不空,消费者便可从缓冲池中取走一个消息。生产者向缓冲池放入消息的同时,消费者不能操作缓冲池,反之亦然。(提示:两个C文件,consumer.c,producer.c),
时间: 2023-11-27 12:50:02 浏览: 123
以下是使用多线程和System V信号量解决生产者消费者问题的示例代码:
producer.c:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define KEY 1234 // 共享内存和信号量的键值
#define BUFFER_SIZE 5 // 缓冲池大小
#define ITEM_COUNT 10 // 生产者生产的消息数量
union semun {
int val; // value for SETVAL
struct semid_ds *buf; // buffer for IPC_STAT, IPC_SET
unsigned short *array; // array for GETALL, SETALL
};
// 定义信号量操作函数
static int sem_op(int sem_id, int sem_num, int op) {
struct sembuf sem_ops;
sem_ops.sem_num = sem_num;
sem_ops.sem_op = op;
sem_ops.sem_flg = 0;
return semop(sem_id, &sem_ops, 1);
}
int main() {
// 获取共享内存和信号量的ID
int shm_id = shmget(KEY, BUFFER_SIZE * sizeof(int), IPC_CREAT | 0666);
int sem_id = semget(KEY, 2, IPC_CREAT | 0666);
if (shm_id == -1 || sem_id == -1) {
perror("Failed to get shared memory or semaphore ID");
exit(1);
}
// 初始化信号量
union semun sem_init_val;
sem_init_val.val = 1;
semctl(sem_id, 0, SETVAL, sem_init_val); // 缓冲区访问信号量
sem_init_val.val = 0;
semctl(sem_id, 1, SETVAL, sem_init_val); // 消息数量信号量
// 获取共享内存指针
int *buffer = (int *) shmat(shm_id, NULL, 0);
if (buffer == (int *) -1) {
perror("Failed to get shared memory pointer");
exit(1);
}
// 生产消息
for (int i = 0; i < ITEM_COUNT; i++) {
sem_op(sem_id, 0, -1); // 获取缓冲区访问信号量
buffer[i % BUFFER_SIZE] = i; // 放入消息
printf("Producer: Produced item %d\n", i);
sem_op(sem_id, 1, 1); // 增加消息数量信号量
sem_op(sem_id, 0, 1); // 释放缓冲区访问信号量
sleep(rand() % 3); // 随机等待一段时间
}
// 分离共享内存指针
shmdt(buffer);
return 0;
}
```
consumer.c:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define KEY 1234 // 共享内存和信号量的键值
#define BUFFER_SIZE 5 // 缓冲池大小
#define ITEM_COUNT 10 // 消费者消费的消息数量
union semun {
int val; // value for SETVAL
struct semid_ds *buf; // buffer for IPC_STAT, IPC_SET
unsigned short *array; // array for GETALL, SETALL
};
// 定义信号量操作函数
static int sem_op(int sem_id, int sem_num, int op) {
struct sembuf sem_ops;
sem_ops.sem_num = sem_num;
sem_ops.sem_op = op;
sem_ops.sem_flg = 0;
return semop(sem_id, &sem_ops, 1);
}
int main() {
// 获取共享内存和信号量的ID
int shm_id = shmget(KEY, BUFFER_SIZE * sizeof(int), IPC_CREAT | 0666);
int sem_id = semget(KEY, 2, IPC_CREAT | 0666);
if (shm_id == -1 || sem_id == -1) {
perror("Failed to get shared memory or semaphore ID");
exit(1);
}
// 获取共享内存指针
int *buffer = (int *) shmat(shm_id, NULL, 0);
if (buffer == (int *) -1) {
perror("Failed to get shared memory pointer");
exit(1);
}
// 消费消息
for (int i = 0; i < ITEM_COUNT; i++) {
sem_op(sem_id, 1, -1); // 获取消息数量信号量
sem_op(sem_id, 0, -1); // 获取缓冲区访问信号量
int item = buffer[i % BUFFER_SIZE]; // 取出消息
printf("Consumer: Consumed item %d\n", item);
sem_op(sem_id, 0, 1); // 释放缓冲区访问信号量
sleep(rand() % 3); // 随机等待一段时间
}
// 分离共享内存指针
shmdt(buffer);
// 删除共享内存和信号量
shmctl(shm_id, IPC_RMID, NULL);
semctl(sem_id, 0, IPC_RMID);
semctl(sem_id, 1, IPC_RMID);
return 0;
}
```
在执行程序之前,需要先运行以下命令创建共享内存和信号量:
```
ipcs -m # 查看共享内存情况
ipcs -s # 查看信号量情况
ipcrm -M 1234 # 删除键值为1234的共享内存
ipcrm -S 1234 # 删除键值为1234的信号量
```
然后可以分别编译和运行producer.c和consumer.c来进行测试。注意在运行多个消费者的时候,需要在不同的终端窗口中运行,以免彼此干扰。
阅读全文