需要帮助才能让以下工作。
我有一个多个生产者线程(每个写入说100个字节的数据)到ringbuffer。 并且一个读取器(消费者)线程,一次读取100个字节并写入stdout。(最后我想根据数据写入文件)
通过这种实现,我有时会从环形缓冲区读取错误的数据。见下文 由于环形缓冲区大小很小,它会变满,一部分数据会丢失。这不是我目前的问题。
**问题:
ringbuffer.h
#define RING_BUFFER_SIZE 500
struct ringbuffer
{
char *buffer;
int wr_pointer;
int rd_pointer;
int size;
int fill_count;
};
ringbuffer.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ringbuffer.h"
int init_ringbuffer(char *rbuffer, struct ringbuffer *rb, size_t size)
{
rb->buffer = rbuffer;
rb->size = size;
rb->rd_pointer = 0;
rb->wr_pointer = 0;
rb->fill_count = 0;
return 0;
}
int rb_get_free_space (struct ringbuffer *rb)
{
return (rb->size - rb->fill_count);
}
int rb_write (struct ringbuffer *rb, unsigned char * buf, int len)
{
int availableSpace;
int i;
availableSpace = rb_get_free_space(rb);
printf("In Write AVAIL SPC=%d\n",availableSpace);
/* Check if Ring Buffer is FULL */
if(len > availableSpace)
{
printf("NO SPACE TO WRITE - RETURN\n");
return -1;
}
i = rb->wr_pointer;
if(i == rb->size) //At the end of Buffer
{
i = 0;
}
else if (i + len > rb->size)
{
memcpy(rb->buffer + i, buf, rb->size - i);
buf += rb->size - i;
len = len - (rb->size - i);
rb->fill_count += len;
i = 0;
}
memcpy(rb->buffer + i, buf, len);
rb->wr_pointer = i + len;
rb->fill_count += len;
printf("w...rb->write=%tx\n", rb->wr_pointer );
printf("w...rb->read=%tx\n", rb->rd_pointer );
printf("w...rb->fill_count=%d\n", rb->fill_count );
return 0;
}
int rb_read (struct ringbuffer *rb, unsigned char * buf, int max)
{
int i;
printf("In Read,Current DATA size in RB=%d\n",rb->fill_count);
/* Check if Ring Buffer is EMPTY */
if(max > rb->fill_count)
{
printf("In Read, RB EMPTY - RETURN\n");
return -1;
}
i = rb->rd_pointer;
if (i == rb->size)
{
i = 0;
}
else if(i + max > rb->size)
{
memcpy(buf, rb->buffer + i, rb->size - i);
buf += rb->size - i;
max = max - (rb->size - i);
rb->fill_count -= max;
i = 0;
}
memcpy(buf, rb->buffer + i, max);
rb->rd_pointer = i + max;
rb->fill_count -= max;
printf("r...rb->write=%tx\n", rb->wr_pointer );
printf("r...rb->read=%tx\n", rb->rd_pointer );
printf("DATA READ ---> %s\n",(char *)buf);
printf("r...rb->fill_count=%d\n", rb->fill_count );
return 0;
}
答案 0 :(得分:0)
在制作人处,您还需要等待has empty space
条件的条件变量。应该无条件地发信号通知两个条件变量,即当消费者从环形缓冲区中移除一个元素时,它应该向生产者发出信号;当生产者在缓冲区放置东西时,它应该向消费者发出信号。
此外,我会将此等待/信令逻辑移动到rb_read和rb_write实现中,因此您的环形缓冲区对于您的其余程序来说是一个“完全使用的解决方案”。
答案 1 :(得分:0)
关于你的问题 - 我也找不到那个错误 - 事实上,我已经尝试过你的代码并且没有看到这种行为。 2.你问这个逻辑/方法是否正确 - 好吧,就其而言,这确实实现了一种环形缓冲区。您的测试用例恰好具有大小的整数倍,并且记录大小是常量,因此这不是最佳测试。
在尝试你的代码时,我发现有很多线程饥饿 - 第一个运行的生成器线程(最后创建的)遇到的事情非常困难,在第5次尝试和失败后将东西放入缓冲区,不给消费者线程一个运行(甚至开始)的机会。然后,当消费者线程启动时,它会在释放cpu之前保持一段时间,并且下一个生产者线程最终启动。这就是它在我的机器上的工作方式 - 在不同的机器上会有所不同,我敢肯定。
现在的代码无法结束 - 创建10或100 MB的文件太难了......难以理解。
答案 2 :(得分:0)
(对于作者来说可能稍后,但如果其他人搜索“多个生产者单个消费者”)
我认为该实现中的基本问题是rb_write修改了一个全局状态(rb-> fill_count和其他rb-> XX),而没有在多个编写器之间进行任何同步。
有关其他想法,请查看:http://www.linuxjournal.com/content/lock-free-multi-producer-multi-consumer-queue-ring-buffer。