【问题标题】:pthread_cancel returning EINPROGRESSpthread_cancel 返回 EINPROGRESS
【发布时间】:2014-06-07 04:09:58
【问题描述】:

我现在正在维护一些代码,它使用pthread_create() 创建一个 pthread。该线程还在创建后不久调用pthread_detach(pthread_self());。此外,它使用pthread_cleanup_push() 推送清理处理程序。该线程唯一的取消点是在线程主循环结束时调用pthread_testcancel()

我现在看到,在某些时候pthread_cancel() 被此线程调用并且(几乎)总是返回一个非零值。在EINPROGRESS 中检查errno 结果。这到底是什么意思?因为手册页声明

成功时,pthread_cancel() 返回 0

不过,它也提到,

该取消将被延迟,直到线程下一次调用作为取消点的函数。

因此,如果返回值非零且 errno 等于 EINPROGRESS 意味着取消请求已排队,但尚未做出反应,我希望情况总是如此。但是如果返回值 0 表示成功,那么它一定意味着不同的东西。

EINPROGRESS 在这种情况下是什么意思,我如何确保线程被正确取消或已经终止?


我在 VM 中运行带有 libpthread-2.13 的 Debian 7.4 作为 libc6:amd64 2.13-38+deb7u1 的一部分。

【问题讨论】:

  • 您在哪个平台、使用哪个版本/实现的 PThreads 观察到这种行为?
  • 感谢您的评论,我更新了我的问题
  • 您在取消调用后立即检查 errno 并且仅当返回码为非零时? EINPROGRESS 不是一个有效的错误,假设 pthread_cancel 是作为一个信号实现的,没有真正的进度需要监控。
  • 是的,这就是代码的作用。抱歉,我的问题是错误的,我说 EINPROGRESS 已返回。实际上返回一个非零值,并且将 errno 设置为 EINPROGRESS。

标签: c multithreading pthreads posix cancellation


【解决方案1】:

线程的可取消状态由 pthread_setcancelstate(3) 确定,可以启用(新线程的默认设置)或禁用。如果线程已禁用取消,则取消请求将保持排队,直到线程启用取消。如果线程启用了取消,则其可取消性类型确定何时发生取消。

-

由 pthread_setcanceltype(3) 确定的线程取消类型可以是异步的或延迟的(新线程的默认值)。异步可取消性意味着线程可以随时取消(通常是立即取消,但系统不保证这一点)。延迟可取消性意味着取消将被延迟,直到线程下一次调用作为取消点的函数。

EINPROGRESS:

在选择了非阻塞模式的对象上启动了无法立即完成的操作。一些必须总是阻塞的函数(例如connect)永远不会返回EAGAIN;相反,它们返回 EINPROGRESS 以指示操作已经开始并且需要一些时间。在调用完成之前尝试操作对象返回 EALREADY。

...how can I make sure, that the thread got canceled correctly 
or was already terminated?

您可以使用 select 函数找出挂起的操作何时完成。

【讨论】:

  • 您的意思是,对于 deferred 的 canceltype 或 disabled 的 cancelstate,pthread_cancel() 返回非零且 errno 等于 EINPROGRESS 完全没问题,并且可以预期?实际上这是有道理的,虽然我发现手册页有点误导。
  • 您能解释一下如何使用 select() 来等待分离的 pthread 终止吗?
【解决方案2】:

我现在看到,在某个时候 pthread_cancel() 会在这个线程上被调用,并且(几乎)总是返回一个非零值。在 EINPROGRESS 中检查 errno 结果。

pthread* 系列函数没有设置errno,而是将错误代码作为函数值返回。

因此,不仅要针对0 测试对pthread_cancel() 的调用结果,还要将返回的值解释为您在errno 中“正常”找到的值,即E* 错误值之一.

int result = pthread_cancel(<some-pthread>);
if (0 != result)
{
  fprintf(stderr, "pthread_cancel() failed with error #%d: '%s'\n", result, strerror(result)); /* Better use strerror_r() in a multithreaded enviroment. */
}

顺便说一句:检查您似乎正在使用的 libc 的来源并没有发现任何 pthread_cancel() 返回 EINPROGRESS 的提示。

【讨论】:

  • 感谢您指出这一点。我认为现有的代码是理所当然的,忽略了 pthread_cancel 确实没有设置 errno。我将不得不检查实际的返回码...
  • 好的,实际返回值告诉我“没有这样的过程”是由其他问题引起的。接受这个作为答案,因为它让我找出了问题的真正原因并指出了代码中的另一个错误。
猜你喜欢
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 2014-04-07
  • 1970-01-01
  • 2015-04-21
  • 1970-01-01
  • 2012-05-01
  • 2015-03-07
相关资源
最近更新 更多