我想设计一个多线程应用程序,它执行以下操作:一个线程依次写入循环缓冲区。然后将有n个读取器线程等待由写入线程发起的某个信号来唤醒并从循环缓冲区读取。信号应该包含一个整数值,表示要读取的循环缓冲区偏移量。在c++中可以这样做吗?任何帮助都将不胜感激。
由于我想要一个设计,可以处理尽可能接近高速,实时的流量,我想消除任何分配/取消内存分配。因此,循环队列将是启动时分配的连续内存块。我不确定你所指的排队是否与此相符。
每次编写代码时,生产者只需要跟踪从哪里开始写入字节循环缓冲区数组。因此,我真正想要的是,当生产者完成了一个包含循环缓冲区中写入的最后一个字节的位置(偏移)的写入事件时,它就可以发布一个“信号”。这将避免需要一个锁定机制。
当接收到此“传播”信号/事件时,使用者线程将唤醒。他们,他们自己,只需要保持跟踪,他们已经停止,然后只是读,直到信号偏移值。最后,生产者和消费者当然需要知道循环缓冲区从哪里开始,以及它有多大,这样他们就知道什么时候包装。
发布于 2013-07-31 16:43:32
根据您最近的编辑,我建议使用有界队列。
有界队列是具有特定长度的队列,因此队列在开始时完全分配,所有元素都将根据元素的默认构造函数进行初始化,或者是null,无论您希望它是什么。
生产者端:如果队列未满,则将一个元素push_back到队列中。
从使用者端:如果队列不是空的,从队列中弹出一个元素并处理它。
您不需要以这种方式在生产者和消费者之间发送消息。事实上,让您的各个线程以某种方式进行通信会产生很多开销,这只会随着更多的线程变得更加复杂。
队列本身需要是线程安全的,关于如何在C++中使线程安全的有界队列有一些例子。
编辑:
你可以把你想要的任何东西都放进队列里。在您的情况下,我建议使用一个指针队列,因为指针的大小在整个执行过程中是不变的。这允许您预先分配队列,但意味着您必须在运行时为您的数据报分配。
你关于线程安全的想法或多或少是正确的。在某些情况下,多个线程访问单个变量是可以的--通常是当它们不是在修改变量,而是只是读取变量时。即使使用循环缓冲区,循环缓冲区也必须是线程安全的,因为任何两个生产者或使用者都将对循环缓冲区进行更改。
尽管如此,每个线程对循环缓冲区或队列的访问时间将非常短--应该有足够的时间将信息复制到数据结构中或从数据结构中复制出来,仅此而已。可以在不从其他线程锁定数据结构的情况下完成对数据的所有其他计算。
如果希望多个线程同时访问数据,则可能需要考虑创建多个队列或缓冲区。每个生产者/消费者对可能有一个循环缓冲区,或者每个输入stream...whatever恰好是一个队列。如果没有一个更具体的例子,很难说。
编辑2
下面是指向线程安全队列的链接。我不确定能不能帮上忙,但看起来很有希望。
发布于 2013-07-29 20:58:04
海事组织,这是一种糟糕的做事方式。让生产者简单地将项添加到循环缓冲区。让每个读取器在循环缓冲区上等待为非空。当非空时,读取器线程只需从缓冲区中移除下一项并对其进行处理。缓冲区本身应该跟踪诸如偏移之类的内容。
至于为什么这样做更好:很大程度上是因为它允许系统的每个部分都做自己的事情,与系统的其他部分进行最少的交互。
在描述系统时,生产者需要知道队列的内部细节,以及使用者线程的所有细节(哪些线程在任何给定时间都要唤醒,哪些线程在任何给定时间处于空闲状态,哪些线程要计划执行任何特定任务,等等)。
我建议的设计最小化使制片人专注于生产。它对系统其余部分的唯一了解包括一件事:一旦产生任务,如何将任务放入队列。
同样,使用者线程只需要知道如何从队列中获取任务,以及如何执行该任务。
队列本身负责所有所需的线程同步。只有当任务被放入/从队列中删除时,才需要同步。队列本身是相当可重用的(可以用于几乎这样的生产者-消费者情况)和可替换(例如,在基于锁的实现和无锁的实现之间非常简单的切换)。
线程调度留给OS -空闲的使用者线程,只需等待队列,操作系统就决定要唤醒哪个线程来执行特定的任务。如果它们中没有一个当前处于空闲状态,操作系统也已经“知道”这一点,并让它们执行当前的处理,直到完成并再次等待队列。
摘要:您所建议的使系统的三个部分都变得更加复杂。更糟糕的是,它将三者交织在一起,因此很难孤立地处理这些部件。
有了这个设计,设计的每一部分都要简单得多,而且每个部分都与其他部分非常隔离,因此每个部分都可以独立地工作、推理等等。
https://stackoverflow.com/questions/17934020
复制相似问题