"pthread_join" 不会 return 在刚刚取消的线程上(使用 "pthread_cancel")
"pthread_join" doesn't return on a just cancelled thread (with "pthread_cancel")
我的程序中有一个线程池 (QueueWorkers
class) 使用此逻辑释放:
int QueueWorkers::stop()
{
for (unsigned int ix = 0; ix < threadIds.size(); ++ix)
{
pthread_cancel(threadIds[ix]);
pthread_join(threadIds[ix], NULL);
}
return 0;
}
其中 threadIds
是类型 std::vector<pthread_t>
的 class 变量。
这个逻辑在大多数情况下都有效,但我已经检查过它有一定概率失败的测试。特别是,有时在执行 pthread_cancel
之后,下一行中的 pthread_join
语句永远不会 returns 并且我的程序挂起。
据我所知,在取消的线程上使用 pthread_join
应该总是 return。是否有任何情况可以避免这种情况或任何调试这里可能发生的事情的方式?我在终止时释放线程的方法是否正确?
附加信息:线程有一个取消处理程序(使用 pthread_cleanup_push
注册),它释放线程使用的动态内存以避免泄漏。在正常情况下,处理程序被调用 pthread_cancel
并且工作正常,但是时间 pthread_join
失败 returning 我已经检查取消处理程序没有被调用。
提前致谢!
编辑: 按照问题评论中的建议,我修改了代码以检查 pthread_cancel
的 returned 值。它始终为 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);
}
注意在开始以太循环之前的pthread_cleanup_push()
语句。这样做是为了在取消 Foo
对象时实现清理逻辑:
static void workerFinishes(void* curl)
{
freeFoo((Foo*) curl);
}
我希望没有过度简化代码。不管怎样,大家可以看到原版here.
确定线程处于取消状态或者您的线程 cancelation_type
是异步的?
来自 pthread_cancel
的 man
:
A thread's cancellation type, determined by
pthread_setcanceltype(3), may be either asynchronous or deferred (the
default for new threads). Asynchronous cancelability means that the
thread can be
canceled at any time (usually immediately, but the system does not guarantee this). Deferred cancelability means that cancellation
will be delayed until the thread next calls a function that is a
cancellation point. A list of functions that are or may be cancellation points is provided in pthreads(7).
我不认为取消线程是确保线程完成的最佳方法。或许您可以向线程发送一条消息,告知它应该停止,并确保线程确实收到消息并将处理它。
我的程序中有一个线程池 (QueueWorkers
class) 使用此逻辑释放:
int QueueWorkers::stop()
{
for (unsigned int ix = 0; ix < threadIds.size(); ++ix)
{
pthread_cancel(threadIds[ix]);
pthread_join(threadIds[ix], NULL);
}
return 0;
}
其中 threadIds
是类型 std::vector<pthread_t>
的 class 变量。
这个逻辑在大多数情况下都有效,但我已经检查过它有一定概率失败的测试。特别是,有时在执行 pthread_cancel
之后,下一行中的 pthread_join
语句永远不会 returns 并且我的程序挂起。
据我所知,在取消的线程上使用 pthread_join
应该总是 return。是否有任何情况可以避免这种情况或任何调试这里可能发生的事情的方式?我在终止时释放线程的方法是否正确?
附加信息:线程有一个取消处理程序(使用 pthread_cleanup_push
注册),它释放线程使用的动态内存以避免泄漏。在正常情况下,处理程序被调用 pthread_cancel
并且工作正常,但是时间 pthread_join
失败 returning 我已经检查取消处理程序没有被调用。
提前致谢!
编辑: 按照问题评论中的建议,我修改了代码以检查 pthread_cancel
的 returned 值。它始终为 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);
}
注意在开始以太循环之前的pthread_cleanup_push()
语句。这样做是为了在取消 Foo
对象时实现清理逻辑:
static void workerFinishes(void* curl)
{
freeFoo((Foo*) curl);
}
我希望没有过度简化代码。不管怎样,大家可以看到原版here.
确定线程处于取消状态或者您的线程 cancelation_type
是异步的?
来自 pthread_cancel
的 man
:
A thread's cancellation type, determined by pthread_setcanceltype(3), may be either asynchronous or deferred (the default for new threads). Asynchronous cancelability means that the thread can be canceled at any time (usually immediately, but the system does not guarantee this). Deferred cancelability means that cancellation will be delayed until the thread next calls a function that is a cancellation point. A list of functions that are or may be cancellation points is provided in pthreads(7).
我不认为取消线程是确保线程完成的最佳方法。或许您可以向线程发送一条消息,告知它应该停止,并确保线程确实收到消息并将处理它。