c ++在线程之间共享状态的最佳方式

时间:2015-02-17 17:24:18

标签: c++ multithreading c++11 mutex atomic

方案如下:线程A继续执行,直到它从线程B收到一个停止信号,该信号一直从控制台读取输入。

实现此目的的最佳方法是什么? 例如,我想我可以将它实现为一个全局变量,线程A每隔一段时间就会检查一次,而线程B可以改为发出“停止”信号,

但我不知道这是否正确。

  • 即使它是正确的,我应该使用“Volatile”还是“Atomic<>”?特别是线程A只读取变量的值,而线程B只写入变量。

  • 如果在线程A读取之后立即从线程B修改变量并不重要(不会引起问题“线程A退出时间有点放松(在信号之后容忍)”?< / p>

  • 线程B是否还有另一种方法可以启动线程A并在需要时停止它?

5 个答案:

答案 0 :(得分:5)

这个问题很可能会被关闭,因为#34;太宽泛了#34;但是我会尝试回答它(以相同的#34;广泛的方式)。

这里唯一可以想象的答案是: &#34;它取决于&#34; (c)中

一般建议: 试试吧,保持简单(KISS principle)。 从一个简单的解决方案开始(如你的情况下的互斥体),如果你发现它不能令人满意,可以用另一个更复杂但更有效/可扩展/可定制/令人愉快的东西(让我们说原子)替换它。如果任何一个证明是不够的,那就进一步增加复杂性(放松原子,添加无锁的东西,建立基于任务的并发,无论你需要什么),直到找到合适的平衡点。

答案 1 :(得分:2)

你真的不想停止一个线程,而是想要在它处于一个好位置时发出信号停止。

它不一定是全局变量。您可以将结构的地址传递给线程。该结构可以包含一个标志。如果另一个线程知道结构的地址,那么它可以改变标志。您可以拥有一个全局结构数组,每个运行一个线程一个。有多种方法可以让多个线程使用相同的数据。

您可以使用信号。如果要关闭的线程正在休眠,这些都很方便。

有些人喜欢使用互斥锁和条件变量。其他人喜欢使用原子操作。如果您只是测试全局int以查看它是否为非零,则通常不需要互斥锁。

在这种情况下,全局int可以正常工作。如果你愿意,你可以让它变得不稳定。这告诉编译器不要以防止外部变化的方式优化变量。大多数编译器假设全局变量在外部发生变化,并且不需要全局变量。我可能会因为没有具体的挥发性而得到很多好处。

您希望确保在线程运行之前将全局清零。

确切地说,到纳秒时,线程A将看到变化是一个不同的问题。如果线程与线程B同时运行,那么一旦进行更改,它就会立即看到它。如果线程A处于睡眠状态,它将看不到任何东西。甚至可能线程B可以在线程A开始之前改变标志。当线程实际被销毁时​​,在线程函数返回后的某个不确定时间发生 - 每当操作系统到达它时。

答案 2 :(得分:1)

volatile可能会起作用,但它不是正确的解决方案。你能做的最好的事情就是检查std :: atomic_bool。

答案 3 :(得分:0)

您可以使用变量来发出信号&#34;停止&#34;就像你已经解释过的那样,但只有在你使用内存栅栏的条件下才能解决。

有关详细信息,请参阅Understanding c++11 memory fences

答案 4 :(得分:0)

您可以使用std::promisestd::future来代替线程之间共享变量,以便清楚地指示信息的流动方式。在最简单的版本中,您将执行以下操作:

void threadFunc(std::future<void> shallQuit) {
    using namespace std::chrono_literals;
    while (shallQuit.wait_for(0ms) == std::future_status::timeout) {
      // process data.
    }
}

void otherFunc() {
    std::promise<void> signalQuit;
    auto myThread = std::thread(threadFunc, signalQuit.get_future());
    // ... do other stuff.
    signalQuit.set_value();
    myThread.join();
}

作为概括,您可以例如将promise<>专用于与void不同的类型,并发送有关为什么要退出线程的信息。