8

我写多线程程序。

TerminateThread我想问和有什么区别ExitThread

这是我WM_DESTROY收到时的代码片段:

void CleanAll()
{
    DWORD dwExit[MAX_THREAD];
    for(int i = 0; i < MAX_THREAD; i++)
    {
        GetExitCodeThread(hThread[i], &dwExit[i]);
        // I used ExitThread(dwExit[i]); previously
        TerminateThread(hThread[i], dwExit[i]);
        CloseHandle(hThread[i]);
    }
}

我以前使用ExitThread()过,但是我的程序在任务管理器中仍然存在,所以我将其更改为TerminateThread()并且我的程序从任务管理器中消失了。

非常感谢任何提前解释。

4

5 回答 5

11

TerminateThread 强制另一个线程退出。你应该不惜一切代价避免调用它,因为它会阻止一个线程死在它的轨道上,而没有任何清理的机会。这包括分配的任何 CRT 内存。

ExitThread 是为了让当前运行的线程干净利落地停止自己。当您在上面调用它时,您可能会强制主 (UI) 线程退出,并可能让正在运行的线程仍然徘徊。因此,您的程序仍在运行,正如任务管理器中所证明的那样。GetExitCodeThread 也可能失败,因为线程实际上并未退出。

但是停止线程的正确方法是通过任何必要的干净方式发出干净的信号,表明它应该退出。 然后在允许主线程退出之前让线程自行退出。在下面的示例中,我使用了一个全局标志来指示线程它们应该退出。但这假设您的线程将始终有机会轮询全局 bool 状态。另一种更简洁的方法是让每个线程在事件句柄上调用 WaitForSingleObject。当事件句柄发出信号时,线程检查全局变量并在需要时退出。

bool global_Need_ToExit;  // use a bool or replace with an event handle the thread shoudl wait on

void CleanAll()
{
    //signal all threads to exit
    global_Need_ToExit = true;

    DWORD dwExit[MAX_THREAD];
    for(int i = 0; i < MAX_THREAD; i++)
    {
        // actually wait for the thread to exit
        WaitForSingleObject(hThread[i], WAIT_INFINITE);

        // get the thread's exit code (I'm not sure why you need it)
        GetExitCodeThread(hThread[i], &dwExit[i]);

        // cleanup the thread
        CloseHandle(hThread[i]);
        hThread[i] = NULL;
    }
}

DWORD __stdcall YourThreadFunction(void* pData)
{

    while (global_Need_To_Exit == false)
    {
        // do more work
    }

    return 0; // same as ExitThread(0);
}
于 2012-12-16T03:52:34.137 回答
4

抱歉,但投票最多的答案是使用 ExitThread,因为它会“干净利落地停止自己”。这是不正确的。文档指出: ExitThread 是在 C 代码中退出线程的首选方法。但是,在 C++ 代码中,线程在调用任何析构函数或执行任何其他自动清理之前退出。因此,在 C++ 代码中,您应该从您的线程函数返回。 我听从一个论坛的建议来使用 ExitThread,然后花了几个小时想知道我所有的内存泄漏是从哪里来的,我很难学到这一点。是的,那是针对 C++ 的,但这就是这个问题的意义所在。实际上,即使对于 C 也有一个警告“链接到静态 C 运行时库 (CRT) 的可执行文件中的线程应该使用 _beginthread 和 _endthread 进行线程管理,而不是 CreateThread 和 ExitThread。如果不这样做,会在线程调用 ExitThread 时导致少量内存泄漏。” 不要在不知道后果的情况下使用 ExitThread!

于 2016-10-21T10:12:49.410 回答
2

当您的线程完成时,您的进程是否应该完成?您描述的问题可能有很多解释。如果要终止整个过程,只需调用ExitProcess.

问题TerminateThread在于这很可能导致内存泄漏。它不关心线程状态,也不关心它分配的资源。它也可能导致死锁,具体取决于您进行同步的方式。换句话说,它不会优雅地终止它。

终止线程的最佳方法是不显式终止它。不要调用TerminateThreadnor ExitThread,而只是return从线程的函数中调用。您可能需要使用原子标志,或触发事件(或其他同步方法)来发出线程应该终止的信号。然后您的线程应定期检查该标志(或事件)并在返回(终止)之前释放所有资源。

于 2012-12-16T03:52:14.137 回答
0

您可以使用 SingleWaitObjects 或 QueueUserAPC 但您必须确保线程停止检查这些异步对象或等待一个结束并正常终止线程..在linux中您可以使用信号

于 2012-12-16T04:33:56.210 回答
0

最终,您需要像查看迷你进程一样查看每个线程(无论如何,这就是它们的底层内容)。为了让它干净地关闭,你需要额外的基础设施让你 - 主线程 - 告诉它停止。

做到这一点的最简单方法是信号系统,POSIX 的发明者很早就发现了它,因此直接在操作系统中公开。这种系统在现实世界中最好的例子是美国邮局。每个代理都有一个唯一的地址,他们可以从该地址发送和接收来自其他地址的邮件(信号),并且由代理决定当他们收到信号时做什么。有些是信息或垃圾,因此会被忽略,而另一些则是高优先级,如果忽略它们,后果自负。

在代码级别,您需要以下内容才能使其正常工作(我已经为图像处理程序构建了其中一些):
1)一些抽象的“事件”或“控制信号”对象。如果足够,请随意使用默认的 Windows 事件或 linux 信号。
2)某种“管道”:操作系统通常会有一个字面内核原语调用一个管道,让一个端拉数据,而另一个端把数据放入。这个家伙通常对于进程中的通信来说是矫枉过正的,但是你的对象需要在概念上是等价的。
3) 线程中的代码从管道中检索信号并对其进行操作。4) 所有线程都识别的“停止”或“取消”信号。

当然,您可以使用 TerminateThread 硬中止线程,就像您可以使用 taskkill 或 CTRL-C 终止进程一样。ExitThread 是一种特定于 Windows 的方式来构建干净的关闭信号,就像我在 (4) 中描述的那样,但您仍然需要 while 循环和“WaitForSingleObject”(3) 以及特定于 Windows 的句柄 (2) 才能使其工作。

于 2014-01-22T21:33:02.497 回答