0

我是多线程的新手。我在 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 分钟后,cancel==true,然后我想立即退出 run(),而不是再等 9 分钟让 runSearch() 完成。

4

5 回答 5

2

您需要在整个搜索操作过程中不断检查标志。像这样的东西:

    void run()
    {
        cancel = false;            
        while (!cancel)
        {
            runSearch();
            //do your thread stuff...
        }
    }
于 2012-07-31T18:40:24.247 回答
1

您提到您不能修改 runSearch()。使用 pthreads 有一个pthread_setcancelstate()函数,但是我不认为这是安全的,尤其是对于需要 RAII 语义的 C++ 代码。

安全线程取消必须是合作的。被取消的代码必须知道取消并且能够自行清理。如果代码不是为此而设计的并且只是被终止,那么您的程序可能会表现出未定义的行为。

出于这个原因,C++ 的 std::thread 不提供任何线程取消方法,而是必须使用其他答案所示的显式取消检查来编写代码。

于 2012-07-31T19:07:37.860 回答
0

基本上你必须轮询cancel各处轮询标志。您可以使用其他技巧,但它们更特定于平台,例如线程取消,或者不像中断那样通用。

并且cancel需要是一个原子变量(例如在 std::atomic 中,或者只是用互斥锁保护它)否则编译器可能只是将值缓存在寄存器中而看不到来自另一个线程的更新。

于 2012-07-31T19:04:18.157 回答
0

创建一个接受动作/委托的通用方法。让每一步都非常小而具体。向通用方法发送您认为是“步骤”的委托/操作。在通用方法中检测取消是否为真,如果为真则返回。因为如果取消步骤很小,线程应该不会花很长时间就死掉。

这是我可以给出的最好的建议,而无需任何步骤的代码。

另请注意:

 void run()
{
    cancel = false;
    runSearch();
    while (!cancel)
    {
        //do your thread stuff...
    }
}

不起作用,因为如果您正在做的不是迭代,它将在检查!取消之前运行整个线程。就像我说的那样,如果您可以添加有关这些步骤的更多详细信息,那么向您提供建议会更容易。在处理要停止或终止的线程时,最好的办法是将代码拆分为非常小的步骤。

于 2012-07-31T18:45:51.327 回答
0

阅读响应是正确的 - 仅仅因为您在线程中调用了阻塞函数并不意味着它神奇地变成了非阻塞调用。该线程可能不会中断程序的其余部分,但它仍然必须等待 runSearch 调用完成。

好的,所以有一些方法可以解决这个问题,但它们不一定可以安全使用。

你可以明确地杀死一个线程。在 Windows 上,您可以使用TerminateThread () 来终止线程执行。听起来不错吧?好吧,除了使用起来非常危险——除非你确切地知道所有资源和调用在被杀死的线程中发生了什么,否则你可能会发现自己的应用程序在下一次拒绝正常工作。例如,如果 runSearch 打开一个数据库连接,则 TerminateThread 调用不会关闭它。这同样适用于内存、加载的 dll 以及它们使用的所有内容。它旨在杀死完全无响应的线程,因此您可以关闭程序并重新启动它。

鉴于上述情况以及您不使用它的强烈建议,下一步是以外部方式调用 runSearch - 如果您在单独的进程中运行阻塞调用,则可以更确定地终止该进程你不会搞砸其他一切。进程死了,清除它的内存、它的堆、任何加载的 dll,一切。所以在你的线程中,调用 CreateProcess 并等待句柄。您需要在 IPC 上使用某种表格(最好不要使用共享内存,因为在您终止进程时重置它可能会很麻烦)将结果传输回您的主应用程序。如果您需要终止此进程,请在其句柄上调用ExitProcess (或退出在 Linux 中)请注意,这些退出调用需要在进程内调用,因此您需要在进程内运行一个线程以进行阻塞调用。您可以在外部终止一个进程,但同样危险 - 不像杀死一个线程那么危险,但您仍然可以偶尔绊倒。(为此使用TerminateProcesskill

于 2012-07-31T19:27:13.280 回答