C++ std::thread::join挂起在析构函数中
我有以下在专用线程上运行函数的代码。除了析构函数外,它工作得很好。对C++ std::thread::join挂起在析构函数中,c++,c++11,C++,C++11,我有以下在专用线程上运行函数的代码。除了析构函数外,它工作得很好。对thread.join()的调用不会返回。我正在使用VS2013 Express 为了使线程正确连接,我应该更改什么 #include <atomic> #include <condition_variable> #include <mutex> #include <thread> #include <vector> namespace { class mai
thread.join()
的调用不会返回。我正在使用VS2013 Express
为了使线程正确连接,我应该更改什么
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>
namespace
{
class main_thread
{
public:
static auto instance() -> main_thread&
{
static main_thread instance_;
return instance_;
}
auto enque(std::function<void()> func) -> void
{
{
std::lock_guard<std::mutex> lock{ mutex_ };
queue_.push_back(func);
}
condition_.notify_one();
}
private:
main_thread()
{
continue_.test_and_set();
thread_ = std::thread{ std::bind(std::mem_fn(&main_thread::run), this) };
}
~main_thread()
{
continue_.clear();
condition_.notify_all();
if (thread_.joinable())
{
thread_.join();
}
}
main_thread(const main_thread &other) = delete;
main_thread(main_thread &&other) = delete;
main_thread& operator=(const main_thread &other) = delete;
main_thread& operator=(main_thread &&other) = delete;
auto run() -> void
{
while (continue_.test_and_set())
{
auto lock = std::unique_lock<std::mutex>{ mutex_ };
//condition_.wait_for(lock, std::chrono::milliseconds(1));
condition_.wait(lock);
for (auto &func : queue_)
{
func();
}
queue_.clear();
}
}
std::condition_variable condition_;
std::mutex mutex_;
std::vector<std::function<void()>> queue_;
std::thread thread_;
std::atomic_flag continue_;
};
}
auto on_main_thread(std::function<void()> func) -> void
{
main_thread::instance().enque(std::move(func));
}
auto on_main_thread_sync(std::function<void()> func) -> void
{
bool done{ false };
on_main_thread([&]{
func();
done = true;
});
while (!done);
}
这避免了主线程同步上的
中的争用问题,但仍会在~主线程中锁定。VisualStudio指出有2个线程,但在main\u thread::run
中都没有,所以我不明白发生了什么。该函数已正确退出,但由于某些原因线程没有结束。您不应该从关键代码段调用外部代码,这很容易导致死锁
如果在调试器中暂停执行,可能会看到一个或多个线程正在等待获取互斥
如果从func()调用的任何代码尝试排队(),您将无法再次获取互斥锁上的唯一锁
一旦条件变量
等待结束,尝试释放锁。作为测试,您可以添加一个额外的作用域,看看这是否有帮助:
while (continue_.test_and_set())
{
std::vector<std::function<void()>> queue;
{
auto lock = std::unique_lock<std::mutex>{ mutex_ };
//condition_.wait_for(lock, std::chrono::milliseconds(1));
condition_.wait(lock);
queue.swap(queue_);
}
for (auto &func : queue)
{
func();
}
}
while(继续测试和设置())
{
向量队列;
{
auto lock=std::unique_lock{mutex};
//条件等待(锁定,标准::时钟::毫秒(1));
条件等待(锁定);
队列交换(队列交换);
}
用于(自动和功能:队列)
{
func();
}
}
关闭时,代码中可能存在活锁。以下交错是可能的:
main() thread thread in run()
check continue_, see it is true
set continue_ = false
notify the condition variable
join
wait on condition variable
在主线程同步上的中的中有一个done
上的数据竞争,它需要是std::atomic
。我不确定这是否是个问题,但这是个问题。我同意这是个问题。我注意到,当我发布这篇文章时。但是,我不认为这是造成我所遇到的特定问题的原因。的可能重复项标记为重复项。我不确定这样做是否正确,但你似乎和这个家伙有同样的问题:这确实解决了问题。这是Microsoft特有的问题,还是GCC和/或Clang做了同样的事情?您通过访问互斥对象之外的队列
引入了数据竞争。感谢您的注意,@Casey。我已将解决方案更新为仅在获取互斥时访问队列。这是我忽略的另一个问题。我很感激你注意到这一点。我在工作中遇到了这种类型的死锁,您可能认为我现在应该知道得更清楚了。我实现了此更改,但它仍然具有相同的行为。当您暂停调试器时,除了加入之外,您的线程还在等待什么?
main() thread thread in run()
check continue_, see it is true
set continue_ = false
notify the condition variable
join
wait on condition variable
class main_thread
{
public:
static auto instance() -> main_thread&
{
static main_thread instance_;
return instance_;
}
auto enque(std::function<void()> func) -> void
{
{
std::lock_guard<std::mutex> lock{ mutex_ };
queue_.push_back(func);
}
condition_.notify_one();
}
private:
main_thread() : continue_{true}
{
thread_ = std::thread{ &main_thread::run, this };
}
~main_thread()
{
{
std::lock_guard<std::mutex> lock{ mutex_ };
continue_ = false;
}
condition_.notify_all();
if (thread_.joinable())
{
thread_.join();
}
}
auto run() -> void
{
std::unique_lock<std::mutex> lock{ mutex_ };
while(continue_)
{
if(queue_.empty())
{
condition_.wait(lock);
continue;
}
std::vector<std::function<void()>> queue;
queue.swap(queue_);
lock.unlock();
for (auto &func : queue)
{
func();
}
lock.lock();
}
}
std::condition_variable condition_;
std::mutex mutex_;
std::vector<std::function<void()>> queue_;
bool continue_;
std::thread thread_;
};