代码之家  ›  专栏  ›  技术社区  ›  Jim Fell

如果线程无法关闭-C++,则应进行正确的清理

  •  4
  • Jim Fell  · 技术社区  · 15 年前

    当我的应用程序准备关闭使用 CreateThread 执行以下算法:

    _bCloseRequested = TRUE;
    dwMsThen = ::GetTickCount();
    
    do
    {
        ::GetExitCodeThread( m_hThread, &dwExitCode );
        dwMsNow = ::GetTickCount();
    }
    while( (dwExitCode == STILL_ACTIVE) && ((dwMsNow - dwMsThen) < 50000UL) );
    

    如果线程未能在分配的5秒钟内关闭,线程句柄应该关闭,还是允许保持打开?谢谢。

    4 回复  |  直到 15 年前
        1
  •  6
  •   Stefan    15 年前

    首先,不要等待这样的线程完成。您只需等待,就会耗尽所有可用的CPU时间,这也有一个缺点,即您的线程需要更长的时间才能完成!

    用这样的方法代替:

    WaitForSingleObject(m_hThread, 50000);
    

    也就是说:是否要让线程继续运行取决于线程的作用。即使你的主应用开始做其他事情,它还能运行吗?它是否有打开的关键内容(文件、连接、数据库等),如果您终止线程,这些内容将保持打开状态?在决定是终止线程还是让线程继续运行之前,必须考虑所有这些问题。

        2
  •  2
  •   Steve Townsend    15 年前

    只需等待线程句柄。如果时间太长,你应该超时并终止你的应用程序,修复任何使线程无法退出的错误。

    static const DWORD TIMEOUT_VALUE(50000);
    
    if (WaitforSingleObject(m_hThread, TIMEOUT_VALUE) != WAIT_OBJECT_0))
    {
      // thread did not exit in time, log and exit process
    }
    
        3
  •  1
  •   John Dibling    15 年前

    好问题。

    有几种方法可以解决这个问题。

    第一种方法是我认为是理想的方法。那就是永远不要终止线程。原因是多方面的,但也有一些大问题:

    1. 如果线程拥有同步对象,则不会释放它们
    2. RAII对象没有机会清理
    3. 分配的内存将无法释放
    4. 如果您正处于certian内核调用的中间,那么可以对整个应用程序进行处理。

    因此,使用这种方法,您将确定线程没有关闭的原因,并解决该问题。你可能会发现问题很严重。您可能会发现死锁、竞争条件等。静态分析有助于发现这些问题。

    理想的方法是你应该一直坚持的方法。在这样做的时候,最好不要使用旋转锁。相反, Wait() 在线程句柄上超时。通过旋转,你会浪费资源,从等待的线程中窃取时间片。

    但在现实世界中,在生产代码中,您需要一个回退度量,以防其他一切都失败。您应该首先尝试使用多个方法来触发线程以使其自行关闭。如果一切都失败了,那就杀了这条线。但是,由于杀死僵尸线程的危险性,一旦完成了这项工作,就应该重新启动整个应用程序。当您杀死一个线程时,您可以将您的进程置于非确定性状态。所以重新开始。记录错误消息,关闭应用程序,然后重新启动。

        4
  •  0
  •   dicroce    15 年前

    两者都没有。您应该修复任何使线程不干净退出的问题,并简单地连接到它上面。其他一切都只是一个黑客。