多线程信号[关闭]
Posted
技术标签:
【中文标题】多线程信号[关闭]【英文标题】:Multithreaded Signalling [closed] 【发布时间】:2013-07-29 20:55:34 【问题描述】:我想设计一个执行以下操作的多线程应用程序: 一个线程顺序写入循环缓冲区。然后会有n个读取线程等待由写入线程发起的某个信号以唤醒并从循环缓冲区中读取。信号应该以某种方式包含一个整数值,该值表示要读取的循环缓冲区偏移量。这可以在 c++ 中完成吗? 任何帮助将不胜感激。
由于我想要一个能够处理尽可能接近高速、实时流量的设计,因此我想消除任何内存分配/解除分配。因此,循环队列将是在启动时分配的连续内存块。我不确定你所说的排队是否符合这个。
生产者只需在每次有内容要写入时跟踪从哪里开始写入循环缓冲区字节数组。 所以我真正要求的是生产者在完成包含写入循环缓冲区中的最后一个字节的位置(偏移量)的写入事件时传播“信号”的方法。这将避免需要锁定机制。
当接收到这个“传播的”信号/事件时,消费者线程将被唤醒。他们自己只需要跟踪他们离开的地方,然后只需阅读直到信号偏移值。 最后,生产者和消费者当然需要知道循环缓冲区从哪里开始以及它有多大,以便他们知道何时包装。
【问题讨论】:
您应该向我们展示您的尝试并描述其行为与您的期望有何不同。 【参考方案1】:IMO,这是一种糟糕的做事方式。让生产者简单地将项目添加到循环缓冲区。让每个读者在循环缓冲区上等待非空。当它非空时,读取器线程只需从缓冲区中删除下一项并处理它。缓冲区本身应该跟踪诸如偏移之类的东西。
为什么这更好:主要是因为它让系统的每个部分做自己的事情,与系统其他部分的交互最少。
当您描述系统时,生产者需要了解队列的内部细节,以及消费者线程的所有细节(哪些线程在任何给定时间唤醒,哪些线程在任何时间空闲给定时间,安排执行任何特定任务等)
我建议的最小化设计让制作人专注于制作。它对系统其余部分的唯一知识包括一件事:一旦产生任务,如何将它们放入队列中。
同样,消费者线程只需要知道如何从队列中获取任务,以及如何执行该任务。
队列本身负责所有需要的线程同步。仅当任务被放入队列/从队列中删除时才需要同步。队列本身非常可重用(可用于几乎这种生产者-消费者情况)和可替换(例如,在基于锁和无锁实现之间相当简单的切换)。
线程调度留给操作系统——空闲的消费者线程只是在队列中等待,操作系统决定唤醒哪个线程来执行特定任务。如果它们当前都没有空闲,则操作系统也已经“知道”这一点,并让它们进行当前处理,直到完成并再次等待队列。
总结:您的建议使系统的三个部分中的每一个都更加复杂。更糟糕的是,它与三者交织在一起,因此很难孤立地处理这些部分。
通过这种设计,设计的每个部分都保持了相当简单,并且它们中的每一个都与其他部分完全隔离,因此每个部分都可以与其他部分隔离开来进行工作、推理等。其他人。
【讨论】:
如果你说某事做事的方式很糟糕,如果你支持它并解释你为什么这么认为,那将是有益的。【参考方案2】:根据您最近的编辑,我建议使用有界队列。
有界队列是一个有特定长度的队列,所以队列一开始就被完整分配,所有元素都将简单地根据元素的默认构造函数进行初始化,或者为null,随心所欲成为。
从生产者方面:如果队列未满,则将一个元素 push_back 到队列中。
从消费者方面:如果队列不为空,则从队列中弹出一个元素并处理它。
您不需要以这种方式在生产者和消费者之间发送消息。事实上,让你的各个线程以某种方式进行通信会产生很多开销,而且线程越多只会变得更加复杂。
队列本身需要是线程安全的,并且有关于如何在 C++ 中制作线程安全有界队列的示例。
编辑:
您可以将任何您想要的东西放入队列中。在您的情况下,我建议使用一个指针队列,因为指针的大小在整个执行过程中将保持不变。这允许您预先分配队列,但意味着您必须在运行时为数据报分配。
您关于线程安全的想法或多或少是正确的。在某些情况下,多个线程可以访问单个变量——通常是在它们不修改变量而只是读取变量时。即使您使用的是循环缓冲区,循环缓冲区也必须是线程安全的,因为任何两个生产者或消费者都会对循环缓冲区进行更改。
话虽如此,每个线程对循环缓冲区或队列所需的访问时间将非常短 - 应该有足够的时间将信息复制到数据结构中或从数据结构中复制出来,仅此而已。您可以在不锁定其他线程的数据结构的情况下对数据进行所有其他计算。
如果您希望多个线程同时访问数据,您可能需要考虑创建多个队列或缓冲区。也许每个生产者/消费者对一个循环缓冲区,或者每个输入流一个队列......不管它发生了什么。没有更具体的例子很难说。
编辑 2
Here's a link to a thread-safe queue。我不确定它是否会有所帮助,但看起来很有希望。
【讨论】:
队列中的项目可以是不同长度的数据报吗?此外,根据我的理解,线程安全意味着一次只有一个线程可以对队列进行操作。我正在努力使用我的方法,虽然有点复杂,但没有这个限制。 @AlKurlansky 我编辑了我的答案。 最后一次交流帮助很大。有界队列方法很有意义。现在我需要使用一个队列类,它有一个等待队列不为空的方法。一个生产者/一个消费者模型对我有用。我不需要在运行时分配数据报。在启动时,我只需要创建一个大的连续内存块,然后将数据报流式传输到其中,在需要时包装等等。每个排队的项目将指向循环缓冲区中的下一个数据报,我可以在其中处理数据报地方。我可以通过反复试验计算出 circ buff 大小。 @AlKurlansky 很高兴为您提供帮助!我最近在类似的场景中使用 boost::mutex 和 boost::condition_variable 做到了这一点,但我似乎找不到对我有帮助的 SO 页面。我发现了另一篇看起来很有希望的文章。我会将链接添加到我的帖子中。以上是关于多线程信号[关闭]的主要内容,如果未能解决你的问题,请参考以下文章