参考
https://blog.csdn.net/BrilliantAntonio/article/details/120606129
分析
- 执行Add操作时,随机产生一个大写英文字母模拟产品,放入缓冲区,同时调整队尾指针end.
- 执行Remove操作时,将当前缓冲区资源清空,同时调整队首指针start.
#define SEMKEY 123
#define SHMKEY 456
#define BUFNUM 10
#define SEMNUM 3/// main /
struct Buffer
{int start, end;char buffer[BUFNUM];
};void Add(struct Buffer *shm)
{char product = 'A' + rand() % 26;printf("producer %d: added product %c into buffer:\t", getpid(), product);shm -> buffer [shm -> end] = product;shm -> end = (shm -> end + 1) % BUFNUM;printf("|%s|\n", shm -> buffer);
}void Remove(struct Buffer *shm)
{char product = shm -> buffer [shm -> start];printf("consumer %d: removed product %c from buffer:\t", getpid(), product);shm -> buffer [shm -> start] = ' ';shm -> start = (shm -> start + 1) % BUFNUM;printf("|%s|\n", shm -> buffer);
}
这两个函数 Add
和 Remove
是模拟生产者-消费者问题中的两个基本操作:一个用于向缓冲区添加产品(或数据),另一个用于从缓冲区移除产品。这两个函数都操作一个共享内存(shm
),该共享内存应该包含一个缓冲区以及两个索引(start
和 end
)来跟踪缓冲区的哪一部分是空的或满的。
下面是对这两个函数的详细解释:
Add
函数
- 生成随机产品:
char product = 'A' + rand() % 26;
这行代码生成一个随机的大写字母(从 ‘A’ 到 ‘Z’)作为模拟的“产品”。 - 打印添加操作:使用
printf
打印出生产者进程ID和添加的产品。 - 向缓冲区添加产品:
shm -> buffer [shm -> end] = product;
这行代码将随机生成的产品放入缓冲区的当前结束位置。 - 更新结束索引:
shm -> end = (shm -> end + 1) % BUFNUM;
这行代码更新结束索引以指向下一个空位置。如果end
已经到达缓冲区的末尾,它会被重置为缓冲区的开始位置(实现循环缓冲区)。 - 打印缓冲区内容:最后,
printf
打印出整个缓冲区的内容。但这里有一个潜在的问题:缓冲区shm -> buffer
被当作字符串处理,但缓冲区中可能包含非打印字符(如空格或其他非ASCII字符),这可能导致输出看起来不是预期的那样。
Remove
函数
- 获取产品:
char product = shm -> buffer [shm -> start];
这行代码从缓冲区的当前开始位置获取产品。 - 打印移除操作:使用
printf
打印出消费者进程ID和移除的产品。 - 清空开始位置:
shm -> buffer [shm -> start] = ' ';
这行代码将开始位置的内容设置为空格(或其他非产品字符)。这用于表示该位置现在是空的。 - 更新开始索引:
shm -> start = (shm -> start + 1) % BUFNUM;
这行代码更新开始索引以指向下一个有产品的位置。如果start
已经到达缓冲区的末尾,它会被重置为缓冲区的开始位置(实现循环缓冲区)。 - 打印缓冲区内容:同样,这里打印出整个缓冲区的内容,但可能存在与
Add
函数相同的问题。
注意事项
- 缓冲区大小:
BUFNUM
应该是在其他地方定义的一个常量,表示缓冲区的大小。
初始化
void *temp = NULL;struct Buffer *shm = NULL;temp = shmat(shmId, 0, 0);if(temp == (void *) -1){printf("share memory attachment failed!\n");exit(EXIT_FAILURE); }shm = (struct Buffer *) temp;shm -> start = 0;shm -> end = 0;for(i = 0; i < BUFNUM; i++){shm -> buffer[i] = ' ';}
使用
第一个信号量为empty,表示缓冲池为空的个数;
第二个信号量为full,表示缓冲池中的产品个数;
第三个信号量为mutex,控制对缓冲池的读取权限。
使用时,
生产者依次刷新 empty(-1)->mutex(-1)->mutex(+1)->full(+1)
消费者依次刷新 full(-1)->mutex(-1)->mutex(+1)->empty(+1)
void Producer(int semId, struct Buffer *shm)
{do{// wait empty region...// wait mutex...Add(shm);// signal mutex...// singal full region...sleep(random() % 2);}while(1);
}void Consumer(int semId, struct Buffer *shm)
{do{// wait full region...// wait mutex...Remove(shm);// signal mutex...// singal empty region......}while(1);
}
总结
这个循环的缓冲器好像也能实现我们的需求