我已经完成了一个Go程序,人类可以在任何时候打断软件来命令它播放。基本上,我有一个算法在另一个线程中运行,每个时刻都有一个“最佳移动”可用,它会不断改进。
我的问题是:如何在无限循环中正确中断线程?
我尝试了一些事情,并决定这样做:
class MyWorker : public QObject
{
Q_OBJECT
public:
MyWorker();
~MyWorker();
public:
ThreadControl * getThreadControl();
public slots:
void work();
private:
void endOfComputation();
private:
ThreadControl * threadControl;
}
class ThreadControl : public QObject
{
Q_OBJECT
public:
ThreadControl();
public:
bool getAbort();
Parameter getParameter();
void setParameter(Parameter & param);
public slots:
void setAbort(bool b);
private:
QMutex mutex;
bool abort;
Parameter param;
};
最后,无限循环被编码为:
void Myworker::work()
{
// ...
forever
{
abort = threadControl->getAbort();
if(abort)
{
break;
}
// ...
}
endOfComputation();
}
然后,正如您所猜测的那样,在main
,我经常致电ThreadControl::setAbort(true)
基本上,我只是在主线程中保留一个指向布尔值的指针,并在我想要时切换它。 (布尔值封装在ThreadControl
中,因此我可以使用互斥锁正确锁定它。到目前为止一切顺利,它对我有用......但对我来说似乎很恶心!切换指向布尔语的指针听起来像......给我编程错误......
问题是网络上的文档主要(完全是?)关于生产者和消费者线程,它们在有限的时间后完成,而不是在被要求时完成。没有开发中断线程,这就是为什么我要问:有更好的方法吗?
答案 0 :(得分:7)
我知道切换标志而不是调用某种专门的方法看起来很难看,但在现实生活中它是最好的方法。专门的方法通常非常危险,例如QThread::terminate()。有些环境提供了现成的标志,因此您不必添加自己的布尔值,例如带有Thread.interrupt()和Thread.interrupted()的Java。 Qt没有这样的东西,也许这也很好,因为在Java中,中断有时会违反直觉。以Thread.interrupted()
和Thread.isInterrupted()
之间的差异为例。这绝对是违反直觉的。除非您查阅文档,否则很难猜出有什么区别。更糟糕的是,由于其中一个是静态的,你可能认为那是的区别,但事实并非如此。此外,旧式IO操作不能在Java中断,但新式NIO可以,这也没有意义。
有时您可以通过使用其他内容来避免使用标记。例如,如果某个线程具有某种要处理的元素的输入队列,则可以使用特殊的end-of-queue元素来指示它应该在那里停止。但有时候没有方便的地方放置它,那就是当你使用布尔标志时。
您可以做的唯一优化代码的方法是用挥发性bool替换互斥锁定。但是,这并不能保证内存访问顺序,所以如果你的线程依赖于volatile写入时发生的事情,你就不应该这样做。或者您可以使用QAtomicInt代替其内存障碍。但是,如果没有显着的性能影响,使用互斥锁也很好,也是最安全的。
我还用以下代码替换循环:
while (!threadControl->getAbort()) {
// ...
答案 1 :(得分:5)
听起来这是一个很好的方法。您还可以查看它是如何成为boost thread的。因为它使用异常来中止线程,所以它允许你使用interruption_point
在几个地方中断线程。使用他们的线程模型,您可以像这样编写线程函数:
void myFunction(){
boost::this_thread::interruption_point();
}
void Myworker::work()
{
// ...
try
{
forever
{
boost::this_thread::interruption_point();
// do some work
boost::this_thread::interruption_point();
// work again
myFunction(); // interruption might be triggered inside this function
}
endOfComputation();
}
catch(boost::thread_interrupted const &){
// The thread has been interrupted
}
}
我认为在内部,他们使用布尔值(每个线程),在调用boost::thread::interrupt()
方法时设置为true。
修改的
我的目标是向您展示增强如何解决此问题。当然,这不适用于您的QThread。我不希望你切换到boost :: thread。
EDIT2 使用QThread进行快速实施:
void function();
class MyWorker : public QThread {
public:
MyWorker() : m_isInterrupted(false) {}
class InterruptionException {
public:
InterruptionException(){}
};
static void interruptionPoint(){
MyWorker * myWorker = dynamic_cast<MyWorker*>(QThread::currentThread());
if(myWorker){
if(myWorker->m_isInterrupted){
throw InterruptionException();
}
}
}
public slots:
void interrupt(){
m_isInterrupted = true;
}
void work(){
try {
while(true){
MyWorker::interruptionPoint();
function();
}
}
catch(InterruptionException const &){
}
}
private:
bool m_isInterrupted;
};
void function(){
MyWorker::interruptionPoint();
}