我的程序中有一个线程池(QueueWorkers
类(,这些线程使用以下逻辑发布:
int QueueWorkers::stop()
{
for (unsigned int ix = 0; ix < threadIds.size(); ++ix)
{
pthread_cancel(threadIds[ix]);
pthread_join(threadIds[ix], NULL);
}
return 0;
}
其中CCD_ 2是类型为CCD_。
这种逻辑在大多数情况下都有效,但我已经检查过测试,它很可能会失败。特别是,有时在执行pthread_cancel
之后,下一行的pthread_join
语句永远不会返回,并且我的程序挂起。
到目前为止,据我所知,在取消的线程上使用pthread_join
应该总是返回的。有没有任何情况可以避免这种情况,或者以任何方式调试这里发生的事情?我在终止时释放线程的方法是正确的吗?
附加信息:线程有一个取消处理程序(使用pthread_cleanup_push
注册(,它释放线程使用的动态内存以避免泄漏。在正常情况下,处理程序在pthread_cancel
上被调用,并且工作正常,但当pthread_join
失败时,我已经检查了取消处理程序是否未被调用。
提前感谢!
编辑:正如问题评论中所建议的,我已经修改了代码以检查pthread_cancel
的返回值。它总是0,无论之后pthread_join
是否按预期工作。
EDIT2:根据对这个问题的一些评论中的要求,让我提供它如何工作的更多细节。
线程池由start()
方法初始化:
int QueueWorkers::start()
{
// numberOfThreads and pQueue are class variables
for (int i = 0; i < numberOfThreads; ++i)
{
pthread_t tid;
pthread_create(&tid, NULL, workerFunc, pQueue);
threadIds.push_back(tid);
}
return 0;
}
启动函数workerFunc()
如下(简化(:
static void* workerFunc(void* pQueue)
{
// Initialize some dynamic objects (Foo for simplification)
Foo* foo = initFoo();
// Set pthread_cancel handler
pthread_cleanup_push(workerFinishes, foo);
// Loop forever
for (;;)
{
// Wait for new item to process on pQueue
... paramsV = ((Queue*) pQueue)->pop();
// Then process it
...
}
// Next statemement never executes but compilation breaks without it. See this note in pthread.h:
// "pthread_cleanup_push and pthread_cleanup_pop are macros and must always be used in
// matching pairs at the same nesting level of braces".
pthread_cleanup_pop(0);
}
在开始ethernel循环之前,请注意pthread_cleanup_push()
语句。这样做是为了在取消Foo
对象时实现清除逻辑:
static void workerFinishes(void* curl)
{
freeFoo((Foo*) curl);
}
我希望不要过度简化代码。无论如何,你可以在这里看到原始版本。
确定线程处于取消状态还是线程cancelation_type
是异步的?
来自pthread_cancel
的man
:
线程的取消类型,由pthread_setcanceltype(3(可以是异步的,也可以是延迟的(新线程的默认值(。异步可取消性意味着线程可以是随时取消(通常是立即取消,但系统不保证(。延期取消意味着取消将被延迟,直到线程下一次调用属于取消点。在pthreads(7(中提供了作为或可以是消除点的函数的列表。
我不认为取消线程是确保线程完成的最佳方法。也许你可以向线程发送一条应该停止的消息,并确保线程确实收到了消息并将处理它