是boost :: lockfree :: Queue(在多线程程序中)可锁定



我正在处理一个程序,其中2 (gstreamer) boost :: 线程和相同数量的 boost :: threads使用 queue 同时使用虚拟应用程序的应用程序。现在,此队列用于同步 gstreamer thread的任务与>其相应的 Dummy Application tread

队列是事件队列:事件是结构

typedef struct EVENT{
    EVENT_TYPE Ev_Type;  // EVENT_TYPE is enum of Events
    EVENT_DATA Ev_Data;  // EVENT_DATA is union of data to be stored for that event
}Event_;

在谷歌搜索时,我遇到了这两个队列的选项: lockfree :: queue & lockfree :: spsc_queue ,建议lockfree::queues用于多线程应用程序。

混乱:为什么要锁定名称?它是否暗示不能(MUTEX)锁定?

另外,请参见此示例,它说'boost :: lockfree :: queue不是锁定&quot&quot'

Mind = Blown ...

好吧,然后我尝试按照示例(上面的链接)尝试实现此队列

class Foo {
protected:
    boost::lockfree::queue<EVENT> mqSttEventQueue;
public:
    unsigned int SetEventIntoQueue(EVENT *psEvent);
};

及其定义为:

unsigned int Foo::SetEventIntoQueue(EVENT *psEvent) {
    if(mqSttEventQueue.push(*psEvent)){
         //notify that event is in queue;
    }
}

这是成功编译的。但是我在黑暗中完全奔跑。

问题:

  • 为什么该示例将队列声明为

    boost::lockfree::queue<int> queue(128);

那是什么 128 是否说队列大小为128(字节/项目)?queue<int>是否在队列中声明数据类型?

  • 为什么它不适用于我的程序

    boost::lockfree::queue<EVENT> mqSttEventQueue(128);

如果我这样声明了,它会在

中获取编译错误
error: expected identifier before numeric constant
boost::lockfree::queue<EVENT> mqSttEventQueue(128);
                                              ^~~

ps: - 我真的不确定要放置什么标题...如果可以的话,请编辑。

为什么名称为lockfree?它是否暗示不能(MUTEX)锁定?

当然,任何东西被锁定;您将MUTEX放在数据结构之外,并使用触摸数据结构的所有线程使用它。

boost::lockfree::queue提供unsynchronized_popunsynchronized_push,以便在您确保只能访问队列的情况下使用。

,但是lockfree::queue和无锁算法/数据结构的主要目的是,它们不需要锁定:多个线程可以安全地编写和/或同时读取。


'lock free;在编程中具有2种含义,导致可能令人困惑,但诸如"此无锁算法"之类的真实陈述不是无锁的&quot。

  • 休闲用法:lockless 的同义词 - 无静音,使用原子负载,商店和RMW操作(如CAS或std::atomic::atomic_fetch_add)实现。例如,请参见无锁编程简介(Jeff Prewhing)。也许每个系统程序员都应该了解并发。

    std::shared_ptr使用无锁的原子操作来管理其控制块。C 11 std::atomic<>为自定义算法提供了无锁的原始图。参见StDatomic。通常在C 11中,通过多个线程对同一变量的不同步访问是未定义的行为。(除非它们全部仅阅读。)但是std::atomic为您提供明确定义的行为,并选择顺序矛盾,获取/释放或放松的内存顺序。

  • 技术计算机科学意思是:永远睡觉或被杀死的线程不会阻止其余的线程。即保证该程序整体的前进进度(至少一个线程)。(无需等待,是线程不必重试的)。参见https://en.wikipedia.org/wiki/non-blocking_algorithm。CAS重试循环是无锁的经典示例,但不再等待。WAIT-WAIT-FREEF是RCU(读取复制)读取线程的内容,或取决于定义,硬件上的atomic_fetch_add将其用作原始的(例如X86 xadd),而不是根据LL/SC或CAS RETRY retry loop的。

最无锁的多阅读器/多作者队列在技术意义上并非没有锁定。通常它们使用圆形缓冲区,而作者则将"索赔"。条目以某种方式(在队列中修复订单)。但是直到作者完成写入条目本身才能阅读。

通过分析其可能的阻塞行为,请参见无锁的进度保证。作者原子上会增加写索引,然后将数据写入数组条目。如果作者在做这些事情之间睡觉,其他作家可以填补以后的条目,而读者被困在等待那些声称但没有书面的条目。(我还没有看过boost::lockfree::queue<T>,但大概是相似的 1 。)

在实践中表现非常出色,作者和读者之间的争论非常低。但是从理论上讲,作家可能会在错误的时刻阻止并停止整个队列。


脚注1:队列的另一个合理选项是链接列表。在这种情况下,您可以完全构建一个新节点,然后尝试将其cas cas列入列表。因此,如果您成功添加它,那么其他线程可以立即读取它,因为您的指针正确设置了。

但是,回收问题(安全地释放其他线程可能正在阅读以查看其他读者是否已经声称它们的内存)在垃圾收集的语言/环境之外非常棘手。(例如Java)


boost::lockfree::queue<int> queue(128);为什么要128?

这是条目中的队列(最大)大小。在这种情况下,int的含量,因为您使用了 queue<int>,duh。如上所述,大多数无锁队列都使用固定尺寸的圆形缓冲区。当需要增长时,它不能像std :: vector一样复制,因为其他线程可以同时读取它。

手册中记录的(boost::lockfree::queue的第一个Google命中),explicit queue(size_type)构造函数尺寸。

您也可以将容量用作模板参数将容量烘烤到该类型中。(因此,容量成为使用队列的任何地方的编译时间常数,而不仅仅是在构造函数呼叫中可以恒定传播的地方。)

班级显然不执行/需要2的大小,因此模板大小参数可以通过让% capacity操作编译为AN和使用掩码而不是分区来更好地优化。

相关内容

  • 没有找到相关文章

最新更新