0

我想设计一个多线程应用程序,它执行以下操作:一个线程顺序写入循环缓冲区。然后会有n个读取线程等待写入线程发起的某个信号唤醒并从循环缓冲区中读取。信号应该以某种方式包含一个整数值,该值表示要读取的循环缓冲区偏移量。这可以在 c++ 中完成吗?任何帮助,将不胜感激。

因为我想要一个可以处理尽可能接近高速、实时流量的设计,所以我想消除任何内存分配/释放。因此,循环队列将是在启动时分配的连续内存块。我不确定你所说的排队是否符合这个。

生产者只需要跟踪每次有东西要写入时从哪里开始写入循环缓冲区字节数组。所以我真正要求的是生产者在完成包含写入循环缓冲区中的最后一个字节的位置(偏移量)的写入事件时传播“信号”的方法。这将避免需要锁定机制。

当接收到这个“传播的”信号/事件时,消费者线程将被唤醒。他们自己只需要跟踪他们离开的地方,然后只需阅读直到信号偏移值。最后,生产者和消费者当然需要知道循环缓冲区从哪里开始以及它有多大,以便他们知道何时进行包装。

4

2 回答 2

3

IMO,这是一种糟糕的做事方式。让生产者简单地将项目添加到循环缓冲区。让每个读者在循环缓冲区上等待非空。当它非空时,读取器线程只需从缓冲区中删除下一项并处理它。缓冲区本身应该跟踪诸如偏移之类的东西。

至于为什么这样做更好:主要是因为它让系统的每个部分做自己的事情,与系统其他部分的交互最少。

当您描述系统时,生产者需要了解队列的内部细节,以及消费者线程的所有细节(哪些线程在任何给定时间唤醒,哪些在任何给定时间空闲,安排执行任何特定任务等)

我建议的最小化设计让制作人专注于制作。它对系统其余部分的唯一了解包括一件事:一旦产生任务,如何将它们放入队列中。

同样,消费者线程只需要知道如何从队列中获取任务,以及如何执行该任务。

队列本身负责所有需要的线程同步。仅当任务被放入队列/从队列中删除时才需要同步。队列本身是非常可重用的(可以用于几乎这种生产者-消费者的情况)和可替换的(例如,在基于锁和无锁实现之间相当简单的切换)。

线程调度留给操作系统——空闲的消费者线程只是在队列中等待,操作系统决定唤醒哪个线程来执行特定任务。如果它们当前都没有空闲,则操作系统也已经“知道”了这一点,并让它们进行当前处理,直到一个完成并再次等待队列。

摘要:您的建议使系统的三个部分中的每一个都更加复杂。更糟糕的是,它将三者交织在一起,因此很难孤立地处理这些部分中的任何一个。

使用这种设计,设计的每个部分都基本上保持简单,并且每个部分都与其他部分完全隔离,因此每个部分都可以在与其他部分隔离的情况下进行处理、推理等。

于 2013-07-29T20:58:04.500 回答
1

根据您最近的编辑,我建议使用有界队列。

有界队列是具有特定长度的队列,因此队列在开始时被完整分配,并且所有元素将简单地基于元素的默认构造函数进行初始化,或者为空,无论你想要它是什么。

从生产者方面:如果队列未满,则将一个元素 push_back 到队列中。

从消费者方面:如果队列不为空,则从队列中弹出一个元素并处理它。

您不需要以这种方式在生产者和消费者之间发送消息。事实上,让你的各种线程以某种方式进行通信会产生很多开销,而且线程越多只会变得更加复杂。

队列本身需要是线程安全的,并且有一些关于如何在 C++ 中创建线程安全有界队列的示例。

编辑:

您可以将任何您想要的东西放入队列中。在您的情况下,我建议使用一个指针队列,因为指针的大小在整个执行过程中将保持不变。这允许您预先分配队列,但意味着您必须在运行时为数据报分配。

您对线程安全的想法或多或少是正确的。在某些情况下,多个线程可以访问单个变量——通常是在它们不修改变量而只是读取变量时。即使您使用循环缓冲区,循环缓冲区也必须是线程安全的,因为任何两个生产者或消费者都会对循环缓冲区进行更改。

话虽如此,每个线程对循环缓冲区或队列所需的访问时间将非常小——应该有足够的时间将信息复制到数据结构中或从数据结构中复制出来,仅此而已。您可以在不锁定其他线程的数据结构的情况下完成所有其他对数据的计算。

如果您希望多个线程一次访问数据,您可能需要考虑创建多个队列或缓冲区。也许每个生产者/消费者对一个循环缓冲区,或者每个输入流一个队列......不管它发生了什么。没有更具体的例子很难说。

编辑 2

这是线程安全队列的链接。我不确定它是否会有所帮助,但它看起来很有希望。

于 2013-07-31T16:43:32.510 回答