C语言中生产者 - 消费者的线程安全环缓冲区

时间:2012-08-28 14:40:06

标签: c data-structures buffer

在C中,我有几个线程产生 long值,一个线程消耗它们。因此,我需要一个以类似方式实现的固定大小的缓冲区,即Wikipedia implementation,以及以线程安全的方式访问它的方法。

总的来说,以下内容应该成立:

  • 添加到完整缓冲区时,应阻止该线程(不覆盖旧值)。
  • 应该阻止使用者线程,直到缓冲区已满 - 它的工作成本很高,并且应该做尽可能多的工作。 (这是否需要双缓冲解决方案?)

我想使用一个尝试过的实现,最好是从库中。有什么想法吗?


动机&说明:

我正在编写JNI代码,处理在堆对象中删除保留为global referencestags

ObjectFree JVMTI事件发生时,我会得到一个long标记,表示我需要使用DeleteGlobalRef释放的全局引用。为此,我需要JNIEnv引用 - 并且真的代价高昂,所以我想缓冲请求并尽可能多地删除。

可能有很多线程收到ObjectFree事件,并且会有一个线程(我的)执行引用删除。

3 个答案:

答案 0 :(得分:1)

您可以使用单个缓冲区,访问时使用互斥锁。您需要跟踪使用的元素数量。对于“信令”,您可以使用条件变量。生产者线程在将数据放入队列时触发的线程;这将释放使用者线程以处理队列直到空。消费者线程清空队列时触发的另一个消息;这表示任何阻塞的生产者线程填充队列。对于消费者,我建议在释放锁之前锁定队列并尽可能取出(以避免过多的锁),特别是因为出列操作简单快速。

<强>更新
一些有用的链接:
* Wikipedia explanation
* POSIX Threads
* MSDN

答案 1 :(得分:1)

两种可能性:

a)malloc()a * Buffer结构,带有一个数组,用于保存一些long和一个索引 - 不需要锁定。让每个生产者线程malloc自己的* Buffer并开始加载它。当生产者线程填充最后一个数组位置时,将* Buffer排队到生产者 - 消费者队列上的消费者线程,并立即将malloc()排队到一个新的* Buffer。消费者获取* Buffers并处理它们然后释放它们(或者将它们排在其他地方,或者将它们推回到池中以供生产者重用)。这可以避免缓冲区本身的任何锁定,只留下P-C队列上的锁定。问题在于,只有偶尔生成长片的生产者才会处理他们的数据,直到他们的* Buffer被填满,这可能需要一些时间,(在这样的线程中你可以在阵列变满之前推掉缓冲区。) / p>

b)声明一个带有数组的Buffer结构来保存一些long和一个索引。使用互斥锁/ futex / CS锁保护。 malloc()只是一个共享*缓冲区并让所有线程获得锁定,推送它们的长度并释放锁定。如果一个线程推入最后一个数组位置,将* Buffer排队到生产者 - 消费者队列上的消费者线程,立即malloc一个新的* Buffer然后释放锁。消费者获取* Buffers并处理它们然后将它们释放(或者将它们排到其他地方,或者将它们推回池中以供生产者重复使用)。

答案 2 :(得分:1)

您可能需要考虑条件。看一下消费者的这段代码:

while( load == 0 )
    pthread_cond_wait( &notEmpty, &mutex );

它的作用是检查加载(存储列表中元素数量的位置)是否为零,如果为零,则等待生产者生成新项目并将其放入清单。
您应该为生产者实现相同的条件(当它想要将项目放入完整列表时)