【问题标题】:How to safely close a THREAD which has a infinite loop in it如何安全地关闭其中包含无限循环的线程
【发布时间】:2015-05-28 21:23:15
【问题描述】:

我正在使用_beginthreadex 函数创建一个线程。我传入的函数地址有一个无限循环 (while(1)) 。我有threadidthreadhandle

我可以使用TerminateThread(threadhandle,1);,但这很危险。

安全的方法是使用_endthreadex杀死线程,但它只能从线程内部使用,我想从外部杀死线程。

所以请建议是否有一种安全的方法可以使用threadidthreadhandle 从外部安全地关闭、结束或终止线程。

【问题讨论】:

  • 你必须修复你的代码,你需要给线程一个退出条件。如有必要,在另一个进程中运行危险且不合作的代码。
  • 这是 c or c++,windows 特定的吗?等等……
  • 添加了 winapi 标签,因为这确实是 Windows 特定的。
  • @UmNyobe 是的,它是 c,c++ windows。
  • @Hans 那是我最不想做的事情,有没有其他方法可以做到这一点。

标签: c++ c multithreading winapi beginthreadex


【解决方案1】:

正确的方法是使用 CreateEvent 创建一个“杀死我”事件,然后在您希望杀死线程时标记此事件。不要让你的线程等待while(1),而是让它等待while(WaitForSingleObject(hevent_killme, 0))。然后你可以简单地让线程回调完成并返回,不需要调用_endthreadex之类的。

回调函数示例:

static DWORD WINAPI thread_callback (LPVOID param)
{
  ...
  while(WaitForSingleObject(hevent_killme, 0) != WAIT_OBJECT_0)
  {
    // do stuff
  }

  return 0;
}

来电者:

HANDLE hevent_killme = CreateEvent(...);
...

void killthread (void)
{
  SetEvent(hevent_killme);
  WaitForSingleObject(hthread_the_thread, INFINITE);
  CloseHandle(hevent_killme);
  CloseHandle(hthread_the_thread);
} 

永远不要使用 TerminateThread。

【讨论】:

  • while(1) 循环在线程函数内部。我不是在等待线程也在无限循环中终止。
  • @lsrawat 是的,我明白这一点,我的答案是根据这个假设写的。我会稍微澄清一下答案。
  • @Israwat - 你不必这样做。 Lundin 建议您检查事件的状态,而不是线程。
  • 使用 bool 变量,然后每次在 while(1) 循环中测试它...?
  • @user9000 对你有好处。然而,这个问题是关于 Windows 特定的 beginthread() 函数,所以你的咆哮是不相关的。如果它让你更快乐,我相信可以用 POSIX 函数编写相同的代码。
【解决方案2】:

你应该 - 从字面上看 - 永远不要使用 TerminateThread() 我什至不是在开玩笑。如果你从外部终止一个线程,所有保留在其中的资源都将被泄露,所有内部访问的状态变量都将处于未确定状态等等。


您的问题的解决方案可能是发出信号让您的线程自行完成。它可以通过线程安全方式更改的 volatile 变量(参见 InterlockedIncrement())、Windows 事件或类似的东西来完成。如果您的线程有消息循环,您甚至可以通过发送消息要求它停止来做到这一点。

【讨论】:

  • 是的,我也在 msdn 上阅读了所有这些内容。但我想可能是如果有办法做到这一点(从外部安全地杀死线程)。实际上,修改线程内的 while 循环是我的最后一个选择。但似乎这是唯一的选择。
  • @Israwat - 相信我,我开发了大量的多线程应用程序(主要是服务器),从外部杀死一个线程是一种非常糟糕的做法,会导致非常头痛。此外,如果您使用 MFC 之类的框架,则会泄漏大量内存,因为 MFC 线程会为后台 MFC 对象保留大量内存。
【解决方案3】:

当线程循环应该运行时,您可以使用while(continue_running),而不是while(1),其中continue_runningTrue。当你想停止线程时,将控制线程设置为continue_runningFalse。当然,请确保使用互斥锁正确保护 continue_running,因为它是一个变量,其值可以从两个线程中修改。

【讨论】:

  • 记得将 'continue_running' 声明为 volatile,否则优化可能会破坏您的代码。 (在 Visual Studio 或 gcc 中,在其他 IDE 中可能会有所不同。)
  • @mg30rg 在大多数 CPU 上,布尔值是原子操作
  • @user9000 - 这不是关于布尔值,而是关于编译器优化。如果您的编译器不了解变量的多线程性质,它可能会缓存/复制/多状态/跳过/等。出于性能原因。
  • 如果只有一个线程将其设置为非零值,而另一个线程读取它,那么这种变量的线程安全可能无论如何都不是问题。 volatile 防止不正确的优化确实是一个好习惯,但我认为现在大多数编译器都不会犯这样的优化假设错误?
  • @mg30rg 确实,多加小心总是一个好主意,您可能还想补充一点, volatile 会导致它始终从内存中读取,因为这是使用 volatile 的原因之一单/多线程应用程序。
猜你喜欢
  • 2020-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-28
相关资源
最近更新 更多