如何有效地将一个偶然遇到的参数传递给子线程?

时间:2018-06-25 18:22:30

标签: c++ multithreading zeromq atomic setsockopt

我想将字符串参数传递给子线程(正在不断读取套接字),然后在该套接字上使用该参数调用setsockopt()

我正在使用ZeroMQ套接字,因此在这里调用setsockopt()not threadsafe,我将从子线程中调用setsockopt()(建议使用here)。参数更新可能仅在数十亿个读取周期中发生一次,因此在孩子的每个周期中添加if结构是有点错误的:

bool new_arg_available;
std::string new_arg;

while(1){
    sub_socket->recv(data);   // . . . . . . a blocking method call
    printData(data)

    ...                       // . . . . . . data can set new_arg_available

    if (new_arg_available){   // . . . . . . synchronization goes here
        sub_socket->setsockopt(ZMQ_SUBSCRIBE, new_arg, ... );
        new_arg_available = false;
    }
}

对我来说,最直接的选择可能是:

  1. 将互斥锁添加到全局名称空间,在父线程中有new_arg可用时将其锁定,并从子线程中将其解锁。

  2. 使用std::atomic<bool>并以与1中相同的方式使用它。

但是,我想通过某种方式实现使孩子可中断,以便可以从if块的末尾消除while(){...}结构。我不介意上下文切换的代价,因为该事件很少发生。

我是C ++的新手,我想在这里学习最佳实践,以及如何以有效的方式实现这一目标。我想在不使用Boost的情况下解决它,我能找到的实现中断线程的唯一示例是使用Boost。

1 个答案:

答案 0 :(得分:2)

欢迎来到零之禅地

ZeroMQ宣传的主要内容是,ZeroMQ的作者从那时起一直提倡避免任何形式的共享-零共享。

鉴于您已经实例化了ZeroMQ基础架构,最好在无IO线程的 PUSH/PULL 传输上使用线程间 inproc:// 类,忘记任何棘手的(b-)锁定。

一侧(注入器)仅 aPushCHANNEL.send( new_arg );
另一个(实施者)仅在需要时aPullCHANNEL.recv() -s或在需要时使用aPullCHANNEL.poll()测试的更聪明的方法,如果使用轮询测试的零等待形式,则最好if aPullCHANNEL.poll( 0 ){...}else{...}

您的架构将变成一个完全分解的,基于多代理角色的干净智能,而没有任何肮脏的死锁(因此从一开始就最好忘记REQ/REP),而无需进行任何跟踪/调试概念上的缺陷,并在适用的情况下以及在地方责任有意识地映射任何此类错误的根本原因以便及时进行适当的错误处理的情况下,检测到所有错误。


NB:是的,ZeroMQ自此设计以来就不需要线程安全性,因为没有什么可共享的(零共享)。 API v4.1 +中的一些最新工作从此零零开始开始衰落,因此人们可能会读到一些有关线程安全性的内容,但正如上面提到的那样,并且它出现在神话般的Pieter HINTJENS的ZeroMQ的几乎每一页上圣经书-“ 已连接代码,第1卷”-最好不要共享任何内容。

ZeroMQ设计是完全异步的,不需要关心基于干净的干净智能多代理异步信令/消息传递体系结构中的锁定,互斥体体操和其他形式的外部引入元素。您将爱上它,因此请继续尝试并阅读本书。这将是艰难的,但对于那些继续发现ZeroMQ零之美的人来说,这将是一笔不小的代价。