怎么说std :: thread要停止?

时间:2017-02-14 12:31:26

标签: c++ multithreading c++11

我有两个问题。

1)我想用无限循环启动一些函数,就像服务器一样工作,并在一个单独的线程中检查消息。但是我想在我想要的时候从父线程关闭它。在这种情况下,我很混淆如何std::futurestd::condition_variable。或者,创建一些全局变量并将其从父线程更改为true / false更好 2)我想要这样的东西。为什么这个例子在运行时崩溃了?

#include <iostream>
#include <chrono>
#include <thread>

#include <future>

std::mutex mu;
bool stopServer = false;

bool serverFunction()
{

    while (true)
    {
        // checking for messages...
        // processing messages

        std::this_thread::sleep_for(std::chrono::seconds(1));

        mu.lock();

        if (stopServer)
            break;

        mu.unlock();
    }

    std::cout << "Exiting func..." << std::endl;

    return true;
}

int main()
{
    std::thread serverThread(serverFunction);

    // some stuff

    system("pause");

    mu.lock();

    stopServer = true;

    mu.unlock();

    serverThread.join();
}

2 个答案:

答案 0 :(得分:4)

  

为什么这个例子在运行时崩溃?

当您离开线程的内部循环时,会使互斥锁处于锁定状态,因此如果再次使用该互斥锁,则父线程可能会被永久阻止。

你应该使用std::unique_lock或类似的东西来避免这样的问题。

答案 1 :(得分:1)

您的互斥锁已锁定。不要在999/1000的情况下手动锁定互斥锁。

在这种情况下,您可以使用std::unique_lock<std::mutex>创建一个可以避免此问题的RAII锁定持有者。只需在作用域中创建它,并将锁定区域结束于作用域的末尾。

{
  std::unique_lock<std::mutex> lock(mu);
  stopServer = true;
}
<{1>}和

中的

main
{ std::unique_lock<std::mutex> lock(mu); if (stopServer) break; } 中的

现在在这种情况下,你的互斥锁毫无意义。去掉它。将serverFunction替换为bool stopServer,并从代码中删除对std::atomic<bool> stopServermutex的所有引用。

可以安全地从不同的线程读取/写入原子变量。

但是,您的代码仍在忙着等待。处理服务器处理消息的正确方法是保护消息队列的条件变量。然后,通过在消息队列中对停止服务器消息(或标志)进行前排队来停止它。

这导致服务器线程几乎不会经常唤醒和无意义地旋转。相反,它会阻塞条件变量(有一些虚假的唤醒,但很少见)并且只有在有新消息或者被告知要关闭时才会真正唤醒。

mu

我们使用template<class T> struct cross_thread_queue { void push( T t ) { { auto l = lock(); data.push_back(std::move(t)); } cv.notify_one(); } boost::optional<T> pop() { auto l = lock(); cv.wait( l, [&]{ return halt || !data.empty(); } ); if (halt) return {}; T r = data.front(); data.pop_front(); return std::move(r); // returning to optional<T>, so we'll explicitly `move` here. } void terminate() { { auto l = lock(); data.clear(); halt = true; } cv.notify_all(); } private: std::mutex m; std::unique_lock<std::mutex> lock() { return std::unique_lock<std::mutex>(m); } bool halt = false; std::deque<T> data; std::condition_variable cv; }; 作为boost::optional的返回类型 - 如果队列暂停,pop返回一个空的可选项。否则,它会阻塞,直到有数据。

您可以将其替换为可选的任何内容,即使是pop,其中第一个元素表示是否有任何要返回的内容,或者std::pair<bool, T>,或std::unique_ptr<T>,或者无数其他选择。

std::experimental::optional

live example