等待线程超时:冻结
waiting for thread with timeout: freeze
我现在什么都听不懂。考虑下一段代码(简化版):
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
const auto k_sleep = std::chrono::seconds{3};
const auto k_wait = std::chrono::seconds{1};
const auto k_repeats = 20u;
void test()
{
std::mutex m;
std::condition_variable c;
bool processed = false;
std::thread worker{[&]() {
std::this_thread::sleep_for(k_sleep);
std::unique_lock<std::mutex> lock(m);
processed = true;
lock.unlock();
c.notify_one();
}};
std::unique_lock<std::mutex> lock(m);
if(c.wait_for(lock, k_wait, [&processed]() {
return processed;
}))
{
worker.join();
std::cout << "done" << std::endl;
}
else
{
worker.detach();
std::cout << "timeout" << std::endl;
}
}
int main()
{
for(auto i = 0u; i < k_repeats; ++i)
test();
}
几个问题:
- 是否存在死锁?
- 我是否正确使用
condition_variable
(以及与thread
相关的所有其他东西)? - 如果一切正常,
timeout
打印多少次?
正如您所看到的,我正在运行线程并等待它(使用condition_variable
)一段时间。等待时间小于线程的执行时间
使用vc++ (Visual Studio 2015, v 19.00.23026)和g++ (v 4.8.2),我打印了timeout
2次,然后我被困在调试器下的worker.join()
上。如果我将k_sleep
增加到较大的值(相对于循环次数较小的k_wait
),例如,30秒-一切都会很好。
为什么会这样呢?如果我做错了什么,请告诉我正确的方法。由于
内存管理有问题:
- 通过lambda中的引用捕获传递给新线程的变量。
- 所有变量(
m
,c
和processed
)都是在堆栈上分配的,当你分离工作线程时,它们将超出作用域。因此,当线程醒来时,它将访问垃圾。
因此,您需要在堆上分配数据,并确保不通过引用捕获变量。我总是喜欢将数据显式地传递给std::thread
。
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <memory>
const auto k_sleep = std::chrono::seconds{ 3 };
const auto k_wait = std::chrono::seconds{ 1 };
const auto k_repeats = 20u;
struct Data
{
std::mutex m;
std::condition_variable c;
bool processed = false;
};
void test()
{
auto data = std::make_shared<Data>();
auto run = [](std::shared_ptr<Data> i_data) {
std::this_thread::sleep_for(k_sleep);
std::unique_lock<std::mutex> lock(i_data->m);
i_data->processed = true;
lock.unlock();
i_data->c.notify_one();
};
std::thread worker{ run, data };
std::unique_lock<std::mutex> lock(data->m);
if (data->c.wait_for(lock, k_wait, [&data]() {
return data->processed;
}))
{
worker.join();
std::cout << "done" << std::endl;
}
else
{
worker.detach();
std::cout << "timeout" << std::endl;
}
}
int main()
{
for (auto i = 0u; i < k_repeats; ++i)
test();
}
相关文章:
- C++减少modbus_connect超时
- 没有超时的C++条件变量
- WIN32:C++,为什么在WM_CLOSE上调用Messagebox函数程序正在冻结
- 如何在C++(VS2010)中设置超时读取USB端口?
- C++卷曲柱在curl_easy_perform超时
- Win32 发送输入鼠标移动滞后并冻结
- ImGui 在单击按钮后冻结
- 如何在Qt 4.8中阻止/忽略/丢弃早于特定超时的用户输入事件
- 如何改进我的代码,使其不会因超时而终止?(黑客排名挑战)
- QWidget UI 在使用 QQuickWidget 时冻结
- 如何防止 std::thread 在 QT 中冻结 GUI?
- C++:函数外部的超时功能
- 使用boost::multiprecision cpp_int左移时出现超时错误
- Adafruit 羽毛RFM69HCW在使用过程中会冻结,需要硬重置
- QTimer 超时不会在单元测试中触发
- 使用单体计时器的pthread_cond_timedwait有时会比预期晚超时
- MFC/C++ ComboBox:禁用下拉列表关闭和打开(UI 冻结)的绘制
- 超时后,线程睡眠不会继续执行
- 模板总和函数冻结字符
- 等待线程超时:冻结