gpt4 book ai didi

c - c 中的一个消费者多个生产者在缓冲区满后恢复时防止竞争

转载 作者:行者123 更新时间:2023-12-02 00:21:23 27 4
gpt4 key购买 nike

我制作了一个循环缓冲区,多个客户端将不同长度的消息写入缓冲区。服务器读出它们。它基于消费者/生产者问题的代码。问题是当缓冲区已满并且服务器从缓冲区中删除所有数据时,客户端收到信号以恢复其写入操作,但另一个客户端(在另一个线程中)开始在缓冲区中写入消息。我希望在缓冲区已满之前已经写入的客户端恢复其操作,以便消息不会乱序到达。

这是我的代码(我删除了很多测试代码)

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define BUFFER_SIZE 8
#define NUM_THREADS 4

struct cBuf{
char *buf;
int size;
int start;
int end;
pthread_mutex_t mutex;
pthread_cond_t buffer_full;
pthread_cond_t buffer_empty;
};

struct cBuf cb;


void buf_Init(struct cBuf *cb, int size) {
int i;
cb->size = size + 1;
cb->start = 0;
cb->end = 0;
cb->buf = (char *)calloc(cb->size, sizeof(char));
for (i=0;i<size;i++) cb->buf[i]='_';

}

void buf_Free(struct cBuf *cb) {
free(cb->buf);
}

int buf_IsFull(struct cBuf *cb) {
return (cb->end + 1) % cb->size == cb->start;
}

int buf_IsEmpty(struct cBuf *cb) {
return cb->end == cb->start;
}

int buf_Insert(struct cBuf *cb, char *elem) {

int i,j;

pthread_mutex_lock(&(cb->mutex));
for (i=0; i < strlen(elem); ++ i){
if (buf_IsFull(cb)==1) printf("\nProducer (buf_Insert) is waiting because of full buffer");
while(buf_IsFull(cb)){
pthread_cond_signal(&(cb->buffer_full));
pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));
}
cb->buf[cb->end] = elem[i];
cb->end = (cb->end + 1) % cb->size;
printf("%c [INPUT]",elem[i]);
}

pthread_cond_signal(&(cb->buffer_full));
pthread_mutex_unlock(&(cb->mutex));
return 0;
}

int buf_Read(struct cBuf *cb, char *out) {
int i,j;

pthread_mutex_lock(&(cb->mutex));
if (buf_IsEmpty(cb))printf("\nConsumer (buf_Read) is waiting because of empty buffer\n");
while(buf_IsEmpty(cb)){
pthread_cond_wait(&(cb->buffer_full),&(cb->mutex));
}
for (i=0;i<BUFFER_SIZE-1;i++){
printf("\n");
if (cb->start == cb->end) break;
out[i] = cb->buf[cb->start];
cb->buf[cb->start] = '_';
cb->start = (cb->start + 1) % cb->size;
printf("%c [OUTPUT]",out[i]);
}
pthread_cond_signal(&(cb->buffer_empty));
pthread_mutex_unlock(&(cb->mutex));
return 0;
}

void * client(void *cb){

pthread_detach(pthread_self());

struct cBuf *myData;
myData = (struct cBuf*) cb;
char input[]="Hello World!";
if (buf_Insert(myData, input)){
//succes on return 0
printf("\n");
}

return 0;
}

int main(void) {
char out[60];
pthread_t thread;
int i;
/* Initialise conditioners*/
pthread_cond_init(&(cb.buffer_full),NULL);
pthread_cond_init(&(cb.buffer_empty),NULL);

buf_Init(&cb, BUFFER_SIZE);

for (i = 0; i<NUM_THREADS; i++){
if(pthread_create (&thread,NULL, client, (void *) &cb) !=0){
} else {

}
}

while (1){
if (buf_Read(&cb,out)){
}
}

//empty the buffer; free the allocated memory
buf_Free(&cb);
return 0;
}

最佳答案

我已经在Producer/consumer seems to be in deadlock when buffer is smaller than input from producer的评论中解释过了,但这些都是评论,所以这里作为答案:

你永远不应该在队列中有部分消息。确保你永远不会写。

您可以在开始写入消息之前检查是否有足够的空间,如果没有则立即等待 buffer_empty,或者您可以更改队列以将共享指针发送到分配的数据(将所有权传递给消费者或引用计数) 之类的,所以每条消息只占用队列中的一个槽,并为其余的分配内存。什么是最好的将取决于您的消息的确切性质。只要没有部分消息,任何事情都可以。

虽然可以记录哪个特定的作者需要完成一条消息并唤醒它,但这会非常复杂。同步很难,但不要通过对其施加额外的要求来让它变得更难。

事实上,除非这是一项家庭作业(从某种意义上说,您这样做是为了了解同步是如何工作的),否则只需寻找现成的消息队列即可。数据报模式下的 SysV-IPC 或 unix 域套接字是我想到的两个选项,或者寻找一些这样做的库。

关于c - c 中的一个消费者多个生产者在缓冲区满后恢复时防止竞争,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10783792/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com