繁体   English   中英

如何说std :: thread停止?

[英]How to say to std::thread to stop?

我有两个问题。

1)我想启动一个具有无限循环的功能,以像服务器一样工作,并在单独的线程中检查消息。 但是我想在需要时从父线程关闭它。 在这种情况std::condition_variable ,我混淆了如何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();
}

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

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

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

您将互斥锁保持锁定状态。 在999/1000情况下,请勿手动锁定互斥锁。

在这种情况下,您可以使用std::unique_lock<std::mutex>创建RAII锁持有者,从而避免此问题。 只需在范围内创建它,并在范围的末尾具有锁定区域即可。

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

main

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

serverFunction

现在,在这种情况下,您的互斥是毫无意义的。 去掉它。 bool stopServer替换为std::atomic<bool> stopServer ,然后从代码中删除对mutexmu所有引用。

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

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

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

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将返回一个空的optional。 否则,它将阻塞直到有数据为止。

您可以将其替换为任何可选的东西,甚至是std::pair<bool, T> ,其中第一个元素表示是否有要返回的内容,或者是std::unique_ptr<T>std::experimental::optional ,或其他多种选择。

cross_thread_queue<int> queue;

bool serverFunction()
{
  while (auto message = queue.pop()) {
    // processing *message
    std::cout << "Processing " << *message << std::endl;
  }

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

  return true;
}

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

  // some stuff
  queue.push(42);

  system("pause");

  queue.terminate();

  serverThread.join();
}

现场例子

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM