使用对象生存期运行线程
Run thread with object lifetime
在我的类A
中,有一个线程的运行时间与对象的生存期一样长。现在,我有一个布尔成员变量,它在每个循环中都会被检查,在析构函数中,这个变量被设置为false。
class A {
public:
A() : mRun(true) {
mThread = std::thread(&A::DoWork(), this);
}
~A() {
mRun = false;
}
private:
bool mRun;
std::thread mThread;
void DoWork() {
while (mRun) {
...
}
}
};
是否可以安全地使用while(true)
?我读到,在销毁线程时,它们将被终止。
"是否可以安全地使用while(true)?">
是的(假设while(true)
实际上意味着while (mRun)
)。您需要确保mRun
成员对于来自不同线程的并发读/写访问是安全的。最简单的方法是使用std::atomic<>
值,如下所示:
class A {
public:
A() : mRun(true) {
mThread = std::thread(&A::DoWork(), this);
}
~A() {
mRun = false; // <<<< Signal the thread loop to stop
mThread.join(); // <<<< Wait for that thread to end
}
private:
std::atomic<bool> mRun; // Use a race condition safe data
// criterium to end that thread loop
std::thread mThread;
void DoWork() {
while (mRun == true) {
...
}
}
};
其中CCD_ 7应当回退到CCD_。
要直接解释如何使OP的问题线程安全,请阅读第一段。其余部分描述了另一种处理退出条件的方法
是的,您可以在代码中安全地使用while(mRun)
。为了使现有的示例线程安全,请调用mthread.join()
,这样线程就不会在线程仍在运行时执行其析构函数。
控制线程执行的另一种方法是使用异常和异常处理程序来转义线程循环。这是通过在循环外使用try-catch语句来实现的。这是boost::thread
使用的方法,因此在您的方法中,您将调用my_thread.interrupt_check()
,这将引发异常。这将允许堆栈展开,并销毁堆栈上的任何对象。但是你必须小心使用这种方法。如果线程中没有捕捉到异常,程序将调用std::terminate
,整个程序将停止。这种方法的一个例子是这样的:
void interrupt_check();
class interruptible_thread
{
private:
static thread_local std::atomic<bool>* interrupt_flag;
friend void interrupt_check();
std::atomic<bool> flag;
std::thread thread_obj;
struct interrupt_exception { };
public:
template<typename _Fn, typename... _Args>
interruptible_thread(_Fn& function, _Args& arguments) :
flag(false),
thread_obj([](std::atomic<bool>* flag_var, _Fn&& function, _Args&& arguments)
{ interrupt_flag = flag_var;
try
{
function(std::forward<_Args>(arguments));
} catch (interrupt_exception& e) { }
},
&interrupt_flag,
std::forward<_Fn>(function),
std::forward<_Args>(arguments))
{ }
void interrupt() { flag = true; }
~interruptible_thread() { flag = false; interrupt(); thread_obj.join(); }
}
void interrupt_check()
{
if(!interruptible_thread::interrupt_flag)
throw interruptible_thread::interrupt_exception;
}
此方法的优点是可以正确执行析构函数,并且可以在调用方希望时终止线程。缺点是,如果线程不进行检查,那么这只是具有更多开销的std::thread
。
还要注意,如果std::thread
对象被破坏,而线程仍然是可连接的,则调用std::terminate
。我想这并不是将线包裹在物体中的意图。
您必须记住,mRun只会设置为false,因为对象正在被销毁。因为它是在自己的线程上,这不是一个好主意。一个更好的想法是使用一个已设置的全局布尔值,该类可以对其使用原子操作,以防止两个线程对其进行写入(例如,线程A将其设置为FALSE,而线程B在其正后方,并将其设置回TRUE,无论出于何种原因——坏主意…),这样,当对象被破坏时,您可以检测到它不再存在,而不尝试访问它。
当我做这样的事情时,我倾向于将线程本身的实例传递到我的RUN函数中,这样我就可以像一样访问它
while(threadInstance->mRun)
但这可能对你不起作用。
- 使用基类中的派生方法运行线程,而无需使用模板
- 使用 ubuntu 终端在 c++ 上运行线程类的问题
- 将项目添加到队列时运行线程
- 运行线程和线程对象之间的关系
- 在 gtest 中运行线程
- 是否有一种可接受的运行线程或按顺序执行的方法
- 从类中运行线程
- 如何在第三方函数调用之前同时运行线程
- 在优先级最低的核心中运行线程
- 在C++中并行运行线程
- 在C 11中的背景中运行线程
- 在运行线程中处理事件
- 使用对象生存期运行线程
- WINAPI CreateThread并不总是运行线程
- 树莓派与 c++ 运行线程,在网络上发布数据
- 使用变量类型 std::function 运行线程
- Eclipse CDT 多线程调试不是最佳的 - 如何以独占方式运行线程
- 在 C 语言的后台运行线程
- 正在运行线程
- 在远程计算机上运行线程