我创建了一个循环缓冲区,其中多个客户端写入(最终我希望它们将不同大小的消息写入)缓冲区。服务器将它们读出来。它基于消费者/生产者问题中的代码:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 10
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));
}
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 ");
while(buf_IsFull(cb)){
pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));
}
cb->buf[cb->end] = elem[i];
cb->end = (cb->end + 1) % cb->size;
printf("%c-",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 ");
while(buf_IsEmpty(cb)){
pthread_cond_wait(&(cb->buffer_full),&(cb->mutex));
}
for (i=0;i<BUFFER_SIZE-1;i++){
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-",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)) printf("\n");
return 0;
}
int main(void) {
char out[60];
pthread_t thread;
int i;
pthread_cond_init(&(cb.buffer_full),NULL);
pthread_cond_init(&(cb.buffer_empty),NULL);
buf_Init(&cb, BUFFER_SIZE);
for (i = 0; i<1; i++){
if(pthread_create (&thread,NULL, client, (void *) &cb) !=0){
#ifdef DEBUG
printf("\nDEBUG (Main Thread) - Error while creating thread");
#endif
} else {
#ifdef DEBUG
printf("\nDEBUG (Main Thread) - Thread created");
#endif
}
}
while (1){
if (buf_Read(&cb,out)) printf ("succes");
}
buf_Free(&cb);
return 0;
}
当缓冲区大于单个客户端的消息时(通过使buffer_size
更大,例如16),它主要起作用。然而,当我把它缩小时,它似乎陷入僵局,即使经过大量研究,我也无法弄清楚原因。当我在调试器中运行代码时,代码似乎在行
pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));
为什么代码在这里停止,如何防止它停止?
答案 0 :(得分:1)
您是否以单数形式说“小于消息”?如果缓冲区不够大,甚至不能存储一条消息,那么生产者将停止将其写入队列中途,并且永远不会通知消费者它有消费的东西。
简要扫描代码似乎证实 - 如果连一条消息都无法写入,则在写入循环中阻塞,并且在函数结束时不进行pthread_cond_signal
调用,因此,您永远不会通知消费者,也无法释放缓冲区。
这个问题是主要的。消费者可以开始消费的基本单位必须适合队列。您可以通过两种方式解决问题 - 确保缓冲区足够大以容纳消息,或者使消息可以在较小的单元中处理,并在每个单元后通知消费者(pthread_cond_signal
)。