怪异的多线程行为 - compilerexplorer链接
tl; dr:为什么这 https://godbolt.org.org.org/z/z/ Z/Z/OHK31HW34 < /a>多线程程序segfault?
说明:我正在遇到多线C ++应用程序的怪异行为。该应用程序具有多个线程,这些线程会在一段时间内通过std :: Atomic&lt; bool&gt;
variable循环循环。我在多个位置使用此构造,因此将其提取到具有start(function)
&amp; amp;的简单threadloop
类中。 stop()
方法。
class ThreadLoop
{
public:
ThreadLoop(const std::string& name) : mName(name) {}
~ThreadLoop() { Stop(); }
template <typename F>
void Start(F&& function)
{
if (mRunning)
return;
std::scoped_lock lock(mMutex);
if (mThread.joinable())
mThread.join();
mRunning = true;
mThread = std::thread([&]() {
while (mRunning)
{
function();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
});
}
void Stop()
{
if (not mRunning)
return;
mRunning = false;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
private:
std::atomic<bool> mRunning = false;
std::mutex mMutex;
std::thread mThread;
std::string mName;
};
然后,我将此自定义类的对象用作不同的“工作”类中的成员,该类别分配了特定函数要定期执行,因此
class Worker1
{
public:
void StartWorking()
{
mThread.Start([this]() { Work(); });
}
void StopWorking() { mThread.Stop(); }
private:
ThreadLoop mThread{"worker1 loop"};
void Work()
{
fmt::print("Working...\n");
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
};
我将所有这些“工人”在另一个类中都有所有这些“工人”,并调用startworking()
/stopworking()
在随机时间点上(也在threadloop
中)
class Main
{
public:
void Start()
{
mThread.Start([this]() { MainLoop(); });
}
void Stop() { mThread.Stop(); }
private:
ThreadLoop mThread{"main loop"};
Worker1 mWorker1;
void MainLoop()
{
if (/*something*/)
mWorker1.StartWorking();
else
mWorker1.StopWorking();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
};
第一个threadloop
(“ main loop”)在中,MAIN
类开始正常,并开始调用/stopworking()
,如预期。 startWorking()
然后触发工人启动自己的threadloop
(“ worker1 loop”),在threadloop :: start(start()函数,例如
`../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion mutex->__data.__owner == 0 failed`
,根据调试器的说法,整个threadloop
对象似乎是非初始化/破坏的(例如,std :: String Mname Mname
变量是空的,是空的,是空的,尽管我总是提供一个非空字符串) - 这可能会导致std :: scoped_lock
失败 - 锁定非初始化/破坏的静音。我的问题是,threadloop
对象是如何/为什么不进行初始化的?我认为我清楚地将其构建为每个worker1
对象中的成员?
TL;DR: Why does this https://godbolt.org/z/ohK31hW34 multithreaded program segfault?
Explanation: I am encountering weird behavior of my multithreaded C++ application. The application has multiple threads that loop in a while loop guarded by an std::atomic<bool>
variable. I use this construct in multiple places, so I extracted it to a simple ThreadLoop
class with Start(function)
& Stop()
methods.
class ThreadLoop
{
public:
ThreadLoop(const std::string& name) : mName(name) {}
~ThreadLoop() { Stop(); }
template <typename F>
void Start(F&& function)
{
if (mRunning)
return;
std::scoped_lock lock(mMutex);
if (mThread.joinable())
mThread.join();
mRunning = true;
mThread = std::thread([&]() {
while (mRunning)
{
function();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
});
}
void Stop()
{
if (not mRunning)
return;
mRunning = false;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
private:
std::atomic<bool> mRunning = false;
std::mutex mMutex;
std::thread mThread;
std::string mName;
};
I then use an object of this custom class as a member in a different 'worker' class that assigns a particular function to be periodically executed, like so
class Worker1
{
public:
void StartWorking()
{
mThread.Start([this]() { Work(); });
}
void StopWorking() { mThread.Stop(); }
private:
ThreadLoop mThread{"worker1 loop"};
void Work()
{
fmt::print("Working...\n");
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
};
I have all of these 'workers' in another class and call StartWorking()
/ StopWorking()
on them at random time points (also in a ThreadLoop
)
class Main
{
public:
void Start()
{
mThread.Start([this]() { MainLoop(); });
}
void Stop() { mThread.Stop(); }
private:
ThreadLoop mThread{"main loop"};
Worker1 mWorker1;
void MainLoop()
{
if (/*something*/)
mWorker1.StartWorking();
else
mWorker1.StopWorking();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
};
The first ThreadLoop
("main loop") in the Main
class starts fine and starts calling StartWorking()
/ StopWorking()
, as expected. The StartWorking()
then triggers the worker to start its own ThreadLoop
("worker1 loop"), which fails undeterministically inside the ThreadLoop::Start()
function, for example via
`../nptl/pthread_mutex_lock.c:81: __pthread_mutex_lock: Assertion mutex->__data.__owner == 0 failed`
Also, according to the debugger, the entire ThreadLoop
object seems to be uninitialized / destroyed (e.g. the std::string mName
variable is empty, although I always provide a non-empty string) - this probably causes the std::scoped_lock
to fail - locking an uninitialized/destroyed mutex. My question is, how/why is the ThreadLoop
object uninitialized? I think I clearly construct it as a member inside each Worker1
object?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题是我正在捕获
t&amp;&amp;函数
通过lambda中的引用threadloop :: start()
,然后将线程调用lambda,这是一个悬空的参考。解决方案是捕获t&amp; amp;功能
按值。原始版本:
固定版本:
甚至更好的版本:
The issue was that I was capturing the
T&& function
by reference in the lambda insideThreadLoop::Start()
, and the thread then invoked the lambda, which was a dangling reference. The fix was to captureT&& function
by value.Original version:
Fixed version:
Even better version: