我是多线程新手。我在unix上使用c ++。
在下面的代码中,runSearch()需要很长时间,我希望能够在“cancel == true”时立即终止搜索。函数cancelSearch由另一个线程调用。
解决此问题的最佳方法是什么?
谢谢你..
------------------这是现有代码------------------------ -
struct SearchTask : public Runnable
{
bool cancel = false;
void cancelSearch()
{
cancel = true;
}
void run()
{
cancel = false;
runSearch();
if (cancel == true)
{
return;
}
//...more steps.
}
}
编辑:为了使其更清晰,请说runSearch()需要10分钟才能运行。 1分钟后,取消== true,然后我想立即退出run()而不是等待另外9分钟让runSearch()完成。
答案 0 :(得分:2)
您需要在整个搜索操作中继续检查标记。像这样:
void run()
{
cancel = false;
while (!cancel)
{
runSearch();
//do your thread stuff...
}
}
答案 1 :(得分:1)
您提到过无法修改runSearch()。使用pthreads有一个pthread_setcancelstate()
函数,但我不相信这是安全的,特别是对于需要RAII语义的C ++代码。
安全线程取消必须合作。取消的代码必须知道取消并能够自行清理。如果代码不是为了做到这一点而被终止,那么你的程序可能会表现出未定义的行为。
由于这个原因,C ++的std :: thread不提供任何线程取消方法,而是必须用其他答案显示的代码来编写代码。
答案 2 :(得分:0)
创建一个接受动作/委托的通用方法。让每一步都变得非常小而具体。向泛型方法发送您认为是“步骤”的委托/操作。在泛型方法中,检测cancel是否为true,如果为true则返回。因为步骤很小,如果取消它,线程就不会花费很长时间。
这是我可以提供的最好的建议,没有任何步骤的代码。
另请注意:
void run()
{
cancel = false;
runSearch();
while (!cancel)
{
//do your thread stuff...
}
}
无法工作,因为如果您正在做的不是迭代,它将在检查之前运行整个线程!取消。就像我说的,如果你可以添加更多关于步骤的详细信息,那么更容易给你建议。使用您想要暂停或终止的线程时,最好的办法是将代码分成很小的步骤。
答案 3 :(得分:0)
基本上你必须在任何地方轮询cancel
标志。您可以使用其他技巧,但它们更具特定于平台,如线程取消,或者不像中断那样通用。
并且cancel
需要是一个原子变量(比如在std :: atomic中,或者只是用互斥锁保护它)否则编译器可能只是将值缓存在寄存器中而不会看到来自另一个的更新线程。
答案 4 :(得分:0)
阅读回答是正确的 - 只是因为你在线程中调用了阻塞函数并不意味着它神奇地变成了非阻塞调用。该线程可能不会中断程序的其余部分,但它仍然必须等待runSearch调用完成。
好的,所以有很多方法可以解决这个问题,但它们并不一定安全。
你可以明确地杀死一个线程。在Windows上,您可以使用TerminateThread()来终止线程执行。听起来不错吧?好吧,除了使用它是非常危险的 - 除非你确切地知道在被杀死的线程中所有的资源和调用是什么,你可能会发现自己有一个拒绝下次正常工作的应用程序。例如,如果runSearch打开数据库连接,则TerminateThread调用不会关闭它。同样适用于内存,加载的dll以及它们使用的所有内容。它专为杀死完全无响应的线程而设计,因此您可以关闭程序并重新启动它。
鉴于上述情况,以及强烈建议你不使用它,下一步是以外部方式调用runSearch - 如果你在一个单独的进程中运行阻塞调用,那么这个进程可以被杀死很多更确定的是,你赢得了其他所有东西。进程终止,清除其内存,堆,任何加载的dll,一切。所以在你的线程中,调用CreateProcess并等待句柄。你在IPC上需要一些表格(可能最好不要使用共享内存,因为当你终止进程时重置它可能会很麻烦)将结果传回主应用程序。如果您需要终止此过程,请在其上设置ExitProcess句柄(或Linux中的exit) 请注意,这些退出调用需要在进程内部调用,因此您需要在进程内运行一个线程来进行阻塞调用。你可以在外部终止一个进程,但同样,它很危险 - 不像杀死一个线程那么危险,但你仍然可以偶尔绊倒。 (对此使用TerminateProcess或kill)