简体   繁体   English

“pthread_join”不会在刚刚取消的线程上返回(使用“pthread_cancel”)

[英]"pthread_join" doesn't return on a just cancelled thread (with "pthread_cancel")

I have a pool of threads ( QueueWorkers class) in my program that are released using this logic:我的程序中有一个线程池( QueueWorkers类),它们使用以下逻辑释放:

int QueueWorkers::stop()
{
  for (unsigned int ix = 0; ix < threadIds.size(); ++ix)
  {
    pthread_cancel(threadIds[ix]);
    pthread_join(threadIds[ix], NULL);
  }

  return 0;
}

where threadIds is a class variable of type std::vector<pthread_t> .其中threadIdsstd::vector<pthread_t>类型的 class 变量。

This logic works most of the times but I have checked testing that it fails with some probability.这个逻辑在大多数情况下都有效,但我已经检查过测试,它有一定的失败概率。 In particular, sometimes after the execution of pthread_cancel the pthread_join statement in the next line never returns and my program hangs.特别是,有时在执行pthread_cancel之后,下一行中的pthread_join语句永远不会返回并且我的程序挂起。

As far as I understand until now, using pthread_join on a cancelled thread should always return.据我了解,在取消的线程上使用pthread_join应该总是返回。 Are there any circumstances that could be avoiding this or any way of debugging what can be going on here?是否有任何情况可以避免这种情况或以任何方式调试这里可能发生的事情? Is my approach to release threads upon termination the right one?我在终止时释放线程的方法是正确的吗?

Additional information: Threads have a cancellation handler (registered using pthread_cleanup_push ) which frees dynamic memory used by the thread to avoid leaks.附加信息:线程有一个取消处理程序(使用pthread_cleanup_push注册),它释放线程使用的动态 memory 以避免泄漏。 Under normal circumstances, the handler is called upon pthread_cancel and works fine, but the time pthread_join fails returning I have checked that the cancellation handler is not invoked.在正常情况下,处理程序在pthread_cancel上被调用并且工作正常,但是pthread_join失败返回的时间我检查了取消处理程序没有被调用。

Thanks in advance!提前致谢!

EDIT: as suggested in question comments, I have modified my code to check the returned value of pthread_cancel .编辑:正如问题评论中所建议的,我已经修改了我的代码以检查pthread_cancel的返回值。 It's always 0, no matter if after that pthread_join works as expected or not.它始终为 0,无论之后pthread_join是否按预期工作。

EDIT2 : as requested in some comment to this question, let me provide more detail of how it works. EDIT2 :根据对此问题的一些评论中的要求,让我提供有关其工作原理的更多详细信息。

The pool of threads is initialized by the start() method:线程池由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;
}

The start function workerFunc() is as follows (simplified):启动function 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);
}

Note the pthread_cleanup_push() statement before starting the ethernal loop.在开始以太循环之前注意pthread_cleanup_push()语句。 This is done to implement the cleanup logic upon cancellation for the Foo object:这样做是为了在取消Foo object 时实现清理逻辑:

static void workerFinishes(void* curl)
{
  freeFoo((Foo*) curl);
}

I hope not having over-simplified the code.我希望不要过度简化代码。 In any case, you can see the original version here .无论如何,您都可以在此处查看原始版本。

Are sure the thread is in a cancelation or your thread cancelation_type is asynchronous?确定线程处于取消状态还是您的线程cancelation_type是异步的?

From man of pthread_cancel :来自pthread_cancelman

A thread's cancellation type, determined by pthread_setcanceltype(3), may be either asynchronous or deferred (the default for new threads).线程的取消类型由 pthread_setcanceltype(3) 确定,可以是异步的或延迟的(新线程的默认值)。 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.延迟可取消性意味着取消将被延迟,直到线程下一次调用作为取消点的 function。 A list of functions that are or may be cancellation points is provided in pthreads(7). pthreads(7) 中提供了可能是取消点的函数列表。

I don't think canceling threads is the best ways to make sure that a thread will finish.我不认为取消线程是确保线程完成的最佳方法。 Perhaps you can send the thread a message that it should stop and make sure the thread does receive the message and will handle it.也许您可以向线程发送一条消息,让它应该停止,并确保线程确实收到了消息并会处理它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM