我正在使用pthreads处理多线程C应用程序。我有一个写入数据库的线程(数据库只能在单个线程中使用),还有几个线程正在收集数据,处理它,然后需要将结果发送到数据库线程进行存储。我在上面提到过,在C中创建一个多编写器安全队列是“可能的”,但是我看到这个提到的每个地方只是说它“对于这个例子来说太复杂了”而只是演示了一个单一编写器的安全队列
我需要以下内容:
编辑:读取线程不应该在空队列上旋转,因为没有写入可能有几分钟的时间,并且有大量写入的短突发。
答案 0 :(得分:16)
当然,有无锁队列。根据你在评论中所说的内容,这里的表现并不重要,因为无论如何你都要为每次写作创建一个帖子。
因此,这是条件变量的标准用例。使自己成为一个包含互斥锁,条件变量,链表(或循环缓冲区,如果你喜欢)的结构,以及取消标志:
write:
lock the mutex
(optionally - check the cancel flag to prevent leaks of stuff on the list)
add the event to the list
signal the condition variable
unlock the mutex
read:
lock the mutex
while (list is empty AND cancel is false):
wait on the condition variable with the mutex
if cancel is false: // or "if list non-empty", depending on cancel semantics
remove an event from the list
unlock the mutex
return event if we have one, else NULL meaning "cancelled"
cancel:
lock the mutex
set the cancel flag
(optionally - dispose of anything on the list, since the reader will quit)
signal the condition variable
unlock the mutex
如果您正在使用带有外部节点的列表,那么您可能希望在互斥锁之外分配内存,只是为了减少其保留的时间。但是,如果您使用可能最简单的侵入式列表节点来设计事件。
编辑:如果在取消时将“信号”更改为“广播”,您还可以支持多个阅读器(没有可获得给定事件的便携式保证)。虽然你不需要它,但它也不会花费任何费用。
答案 1 :(得分:5)
如果你不需要一个无锁的队列,那么你可以用锁来包装一个现有的队列。
Mutex myQueueLock;
Queue myQueue;
void mtQueuePush(int value)
{
lock(myQueueLock);
queuePush(myQueue, value);
unlock(myQueueLock);
}
int mtQueueNext()
{
lock(myQueueLock);
int value = queueFront(myQueue);
queuePop(myQueue);
unlock(myQueueLock);
return value;
}
之后唯一的事情是在队列为空时为mtQueueNext添加某种handeling。
编辑: 如果您有一个读取器,单个写入器无锁队列,您只需要锁定mtQueuePush,以防止多个同时写入器。
Theres是单个读取器/写入器无锁队列的nubmer,其中大多数都是作为c ++模板类实现的。但是,谷歌搜索,如果需要解决如何在普通C中重写它们。
答案 2 :(得分:4)
答案 3 :(得分:1)
我会选择多个单作家队列(每个作家线程一个)。然后,您可以检查this如何让单个读者阅读各种队列。