我创建了一个自定义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)
)?此外,还有比这更好的方法吗?
答案 0 :(得分:6)
在线程方法结束时调用_endthreadex(0)
很好。它也是可选的。如果你只是正常地离开线程方法,那么就会为你调用_endthreadex(0)
。
您可以显式调用_endthread或_endthreadex来终止线程;但是,当线程从作为参数传递的例程返回到_beginthread或_beginthreadex时,会自动调用_endthread或_endthreadex。 ref
发送终止任务是使阻塞的线程池线程解除阻塞并退出的正确方法。
所以,总结一下:
TerminationTask::Run
的实施是正确的。_endthreadex(0)
结束时删除对ThreadPool::Loop
的无害呼叫。答案 1 :(得分:0)
在队列中放置一个temination任务是正确的。不过,我会尝试不同的方法来处理它:
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
}
}
}