如何用阻塞调用控制线程的执行
How to control the execution of a thread with blocking call
很抱歉,我找不到一个能清楚描述问题的标题。
请阅读下面的片段。有2个线程,其中第一个线程控制执行,第二个线程完成工作。
std::atomic<bool> m_running;
Process* process; // A thread-safe process implementation
//thread 1
void stop()
{
m_running = false;
if( process->isRunning() )
process->kill(); // process->join() returns as a result of this call
}
//thread 2
void run()
{
m_running = true;
while( m_running )
{
do_something();
process->start();
process->join(); // Blocking call
}
m_running = false;
}
我注意到,如果第一个线程开始执行,而第二个线程忙于do_something()
,它会将false
分配给m_running
,并检查进程是否正在运行。由于第二个线程仍然在do_something()
调用中,process->isRunning()
将返回false
,而第一个线程将返回而不杀死进程。
但是第二个线程将在完成do_something()
后立即启动进程,而不是我们的停止要求。
我想到的第一件事是:
//thread 2
void run()
{
m_running = true;
while( m_running )
{
do_something();
if( m_running )
{
// flagged line ...
process->start();
}
process->join(); // Blocking call
}
m_running = false;
}
但是仍然有可能当第二个线程在标记行中中断时,线程1中的整个stop()
方法可以启动和结束。
所以我决定使用互斥锁,但我不确定是否一切正常:
//thread 1
void stop()
{
mutex.lock();
m_running = false;
if( process->isRunning() )
process->kill(); // process->join() returns as a result of this call
mutex.unlock();
}
//thread 2
void run()
{
m_running = true;
while( m_running )
{
do_something();
mutex.lock();
if( m_running )
{
process->start();
}
mutex.unlock();
process->join(); // Blocking call
}
m_running = false;
}
从不可分割的事务角度来考虑。
//thread 1
void stop()
{
m_running = false;
{
//This block should happen as a transaction
std::lock_guard<std::mutex> lck(m_mutex);
if( process->isRunning() )
process->kill();
}
}
//thread 2
void run()
{
m_running = true;
while( m_running )
{
do_something();
{
//Since starting this process depends on m_running
//which could change anytime since we tested it last,
//we test it again, and start, this time as another transaction
std::lock_guard<std::mutex> lck(m_mutex);
if(m_running)
process->start();
}
process->join(); // Blocking call
}
}
您不需要为保护m_running
而烦恼,因为它是默认的std::atomic<bool>
, 顺序一致
虽然更精确的答案需要更多关于isRunning()
, kill()
和join()
的细节,但这里有一个明显的设计缺陷。
也就是说,m_running
标志的目的是重载。
像m_running
这样的标志通常实现两种经典设计模式之一:
- 报告线程的状态:是否正在运行。
或:
- 控制当前线程是运行还是停止。
所示代码试图将两种设计模式合并在一起。而且它们不相交。
如果m_running
的目的是让有问题的线程报告其当前状态,那么线程1的stop()
没有业务设置此标志。m_running
应该只由所讨论的线程更新,并且,实际上,您的线程的run()
在开始时将其设置为true
,在返回之前将其设置为false
。但是,run()
本身没有必要检查if
语句中m_running
的值。它的唯一目的是报告线程的状态。不让线程做任何事情。
在这种设计模式下,kill()
通常实现了一些终止线程执行的方法,通常是通过向线程发送某种类型的消息来告诉线程停止执行。然后kill()
将监视并等待,直到线程服从,并将m_running
设置为false,表示它退出。或者,如果这是一个可接合的线程,kill()
将加入该线程。
或者,m_running
的目的可以是通知线程停止它正在做的事情。但是在这种情况下,执行线程的run()
没有必要更新m_running
本身。在这种设计模式中,线程通常所做的就是执行while(m_running)
循环,等待下一个消息。停止线程的典型过程包括设置m_running
,然后向线程发送某种no-op消息——该消息的唯一目的是唤醒线程,以便它可以通过循环并查看m_running
的更新值。
所示代码试图将两种设计模式合并为一个变量,在我看来,这是设计问题的根本原因。
将m_running
分离为两个独立的变量:一个用于报告线程的状态(如果需要的话),另一个变量用作有序关闭线程的可靠机制的一部分。
- 当我在其中一个线程执行中(在activemq-cpp中)捕获到特定值时,我如何终止/停止所有其他线程
- C++线程:如何在一个线程仍在运行时阻止另一个线程执行 (Win32)
- 在给定时间段内,线程执行的指令数量是否有最小数量?
- 如何在C++中停止线程执行
- 为什么Win API线程执行函数,而标准线程则没有
- 线程执行在IDE中和C 中的EXE应用程序中是否有所不同
- 从线程执行的函数中返回结构数组
- 为什么在从线程执行方法时使用QMetaObject::invokeMethod
- 只有一个线程执行 CUDA 内核
- C++ 多线程:执行顺序
- async_connect()超时,多个线程执行io_service.run()
- 是否可以将线程执行转移到另一个线程?
- 具有随机数总和的多线程执行时间
- 如何 在没有 Boost 的情况下将 C++ 成员函数作为线程执行
- openMP 在自定义容器中从 2 到 4 个线程执行二进制搜索时速度变慢
- 如何使生成的线程拖延足够长的时间以使生成线程执行某些操作
- 远程线程执行
- C++中的基本多线程(执行顺序)
- 线程池中的C++线程执行顺序
- 锁定由不同线程执行的多个函数