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

How to efficiently pass an argument, just very occasionally met, to a child thread?

我想将字符串参数传递给 child 线程(持续读取套接字)并在该套接字上调用带有该参数的 setsockopt()

我正在使用 ZeroMQ 套接字,所以调用 setsockopt()not threadsafe here, I'd call the setsockopt() from the child thread ( as was recommended here )。参数更新可能在数十亿个读取周期中只发生一次,并且将 if 结构添加到 child 的每个周期中感觉有点不对,如下所示:

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. 向全局命名空间添加互斥量,当 parent 线程中可用 new_arg 时将其锁定,并从 child 线程解锁。

  2. 使用一个std::atomic<bool>,使用方法同1.

然而,我想以某种方式实现的是使 child 可中断,这样我就可以从 while(){...} 块的末尾消除 if 结构。我不介意上下文切换的惩罚,因为这种事件很少见。

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

欢迎来到零之禅之地

关于 ZeroMQ 传播的主要评论是,ZeroMQ 作者从那时起就提倡避免任何形式的共享 - 零共享。

鉴于您已经实例化了 ZeroMQ 基础结构,最好使用线程间 PUSH/PULL 而不是 IO 线程 inproc:// transport-class 并忘记任何棘手的 (b-) 锁定。

一侧(喷油器)只是aPushCHANNEL.send( new_arg );
和另一个( Implementor )只是根据需要/需要时 aPullCHANNEL.recv()-s ,或者可以使用更智能的 aPullCHANNEL.poll()-testing 方法,最好还是使用轮询测试的零等待形式if aPullCHANNEL.poll( 0 ){...}else{...}

并且您的 架构变成​​了一个完全分解的、基于多代理角色的干净和智能的,没有任何肮脏的死锁(所以最好从一开始就忘记 REQ/REP),没有任何困难trace/debug 概念上的缺陷和所有错误都会在适用的情况下被检测到,并且在本地责任有意义的情况下映射任何此类错误的根本原因以进行即时错误处理。


注意: 是的,从那以后 ZeroMQ 的设计就不需要线程安全,因为没有什么可以共享(零共享)。最近在 API v4.1+ 中的一些努力开始从零禅开始下降,所以人们可能会读到线程安全的某些方面,但正如上面提到的,并且几乎出现在精彩的每一页上Pieter HINTJENS 的 ZeroMQ 圣经 - “Code Connected,第 1 卷” - 最好什么都不分享。

ZeroMQ 设计是完全异步的,不需要关心锁定、互斥体操和其他形式的外部引入的元素,在一个干净、智能的基于多代理异步信号/消息传递的 架构中。你会爱上它的,所以继续尝试并阅读这本书。这将是艰难的,但对于那些将继续并发现 ZeroMQ Zen-of-Zero 之美的人来说,它会付出很多。