[英]How to say to std::thread to stop?
我有两个问题。
1)我想启动一个具有无限循环的功能,以像服务器一样工作,并在单独的线程中检查消息。 但是我想在需要时从父线程关闭它。 在这种情况std::condition_variable
,我混淆了如何std::future
或std::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
,然后从代码中删除对mutex
和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将返回一个空的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.