如何停止win32线程阻塞



我创建了一个自定义的ThreadPool,它用_beginthreadex()启动了许多win32线程。线程正在运行一个简单的循环,试图从阻塞队列中取出队列任务,但有时我需要停止线程,如果它们在Dequeue上被阻塞,那么我不知道如何使线程脱离阻塞状态。

void ThreadPool::Loop()
{
    while(_running)
    {
        try
        {
            // Attempts to dequeue a task and run it
            _taskQueue.Dequeue()->Run();
        }
        catch(BlockingQueueTerminate&)
        {
            // Eat the exception and check the running flag
            continue;
        }
    }
}

我的想法是排队相同数量的特殊任务(让我们称之为"终止任务"),因为池中有线程,每个"终止任务"将调用_endthreadex(0)以退出线程。如果阻塞队列中有其他任务,那么我就不会真正关心,因为一旦我解除了一个任务的队列,我就会运行它,并检查_running标志,以确定线程是否需要解除任何其他任务的队列。

void TerminationTask::Run()
{
    _endthreadex(0);
}

我对这种方法有几个顾虑;主要是,如果我处理了一个非终止任务,并且_running标志被设置为false,那么我的线程在退出循环时将不会调用_endthreadex(0)。我想知道我是否可以在循环结束时像这样调用_endthreadex(0):

void ThreadPool::Loop()
{
    while(_running)
    {
        try
        {
            // Attempts to dequeue a task and run it
            _taskQueue.Dequeue()->Run();
        }
        catch(BlockingQueueTerminate&)
        {
            // Eat the exception and check the running flag
            continue;
        }
    }
    _endthreadex(0);
}

这会导致与我的TerminationTask冲突,或者线程在执行TerminationTask::Run()后直接退出循环(即它不会调用_endthreadex(0)两次)?此外,还有比这更好的方法吗?

在线程方法结束时调用_endthreadex(0)是可以的。它也是可选的。如果您只是正常离开线程方法,那么_endthreadex(0)将为您调用。

可以显式调用_endthread或_endthreadex来终止线程;然而,当线程从作为参数传递给_beginthread或_beginthreadx的例程返回时,会自动调用_endthread或_endthreadx。ref

发送终止任务是让阻塞的线程池线程解除阻塞并退出的正确方法。

总结一下:

  1. 你们的策略是好的,TerminationTask::Run的实施是正确的。
  2. 可以在ThreadPool::Loop的末尾删除对_endthreadex(0)的无害呼叫。

将终止任务放入队列是正确的。不过,我会尝试一种不同的方法来处理它:

class TerminateThreadNow {};
void TerminationTask::Run()
{
    throw TerminateThreadNow();
} 
void ThreadPool::Loop()
{
    while(_running)
    {
        try
        {
            // Attempts to dequeue a task and run it
            _taskQueue.Dequeue()->Run();
        }
        catch(TerminateThreadNow&)
        {
            _running = false;
        }
        catch(BlockingQueueTerminate&)
        {
            // Eat the exception and check the running flag
        }
    }
} 

最新更新