首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >pthread_exit()和pthread_cancel()如何调用Linux中的清理例程?

pthread_exit()和pthread_cancel()如何调用Linux中的清理例程?
EN

Stack Overflow用户
提问于 2020-05-18 10:01:27
回答 1查看 589关注 0票数 2

我在学习pthread_cleanup_push的概念时观察到,pthread_exit()和pthread_cancel()对pthread_cleanup_pop()有不同的影响。下面是代码示例。

代码语言:javascript
运行
复制
void push_routine_1(void * arg) {
    printf(" Push Routine 1\n");
}

void push_routine_2(void * arg) {
    printf(" Push Routine 2\n");
}

void push_routine_3(void * arg) {
    printf(" Push Routine 3\n");
}

void push_routine_4(void * arg) {
    printf(" Push Routine 4\n");
}

void * thread_routine(void * arg) {
    pthread_cleanup_push(push_routine_1, NULL);
    pthread_cleanup_push(push_routine_2, NULL);
    pthread_cleanup_push(push_routine_3, NULL);
    pthread_cleanup_push(push_routine_4, NULL);

    pthread_exit(NULL);

    pthread_cleanup_pop(1);
    pthread_cleanup_pop(1);
    pthread_cleanup_pop(1);
    pthread_cleanup_pop(1);
}

上面的程序提供了这样的输出:

代码语言:javascript
运行
复制
Push Routine 4
Push Routine 3 
Push Routine 2 
Push Routine 1

当使用pthread_cancel(pthread_self())而不是pthread_exit(NULL)时,输出如下所示

代码语言:javascript
运行
复制
Push Routine 3 
Push Routine 2 
Push Routine 1

在使用push_routine_4()时不执行pthread_cancel()的原因是什么

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-19 13:47:56

我认为您可能不认为pthread_cancel(pthread_self())pthread_exit(NULL)完全相同。

POSIX没有告诉我期望pthread_cancel(pthread_self())做什么。但我注意到它说:

2.9.5线程取消

线程取消机制允许线程以受控的方式终止进程中任何其他线程的执行。

“任何其他线程”都会让我好奇。但我不认为这是问题所在。

默认的‘可取消类型’是PTHREAD_CANCEL_DEFERRED。因此,在取消线程中的下一个“取消点”之前,pthread_cancel()不会生效。因此,您的代码将继续到第一个pthread_cleanup_pop(1),它不是‘取消点’,然后是printf(" Push Routine 4\n"),后者可能是‘取消点’。

我调整了您的代码如下:

代码语言:javascript
运行
复制
static volatile unsigned step ;

void push_routine_1(void * arg) {
  step += 10 ;
  printf(" Push Routine 1 -- %u\n", step);
  step += 10 ;
}

void push_routine_2(void * arg) {
  step += 100 ;
  printf(" Push Routine 2 -- %u\n", step);
  step += 100 ;
}

void push_routine_3(void * arg) {
  step += 1000 ;
  printf(" Push Routine 3 -- %u\n", step);
  step += 1000 ;
}

void push_routine_4(void * arg) {
  step += 10000 ;
  printf(" Push Routine 4 -- %u\n", step);
  step += 10000 ;
}

void * thread_routine(void * arg)
{
  unsigned frag = *(unsigned*)arg ;

  printf("Start %u\n", frag) ;

  step = 0 ;
  pthread_cleanup_push(push_routine_1, NULL); step += 10 ;
  pthread_cleanup_push(push_routine_2, NULL); step += 100;
  pthread_cleanup_push(push_routine_3, NULL); step += 1000 ;
  pthread_cleanup_push(push_routine_4, NULL); step += 10000 ;

  step++ ;
  if (frag == 0)
    pthread_exit(NULL) ;        // 11111
  else
    pthread_cancel(pthread_self()) ;

  step++ ;                      // 11112

  if (frag == 2)
    printf(" Continue %u\n", step) ;

  step++ ;                      // 11113
  pthread_cleanup_pop(1);       // (4)
  step++ ;                      // xxxx4
  pthread_cleanup_pop(1);       // (3)
  step++ ;                      // xxxx5
  pthread_cleanup_pop(1);       // (2)
  step++ ;                      // xxxx6
  pthread_cleanup_pop(1);       // (1)
  step++ ;                      // xxxx7
}

int
main(Unused int argc, Unused char* argv[])
{
  unsigned frag ;

  for (frag = 0 ; frag < 3 ; ++frag)
    {
      pthread_t thr ;

      pthread_create(&thr, NULL, thread_routine, &frag) ;
      pthread_join(thr, NULL) ;

      printf(" Finally %u\n", step) ;
    } ;

  return 0 ;
}

结果是:

代码语言:javascript
运行
复制
Start 0
 Push Routine 4 -- 21111
 Push Routine 3 -- 32111
 Push Routine 2 -- 33211
 Push Routine 1 -- 33321
 Finally 33331
Start 1
 Push Routine 4 -- 21113
 Push Routine 3 -- 22113
 Push Routine 2 -- 23213
 Push Routine 1 -- 23323
 Finally 23333
Start 2
 Continue 11112
 Push Routine 4 -- 21112
 Push Routine 3 -- 32112
 Push Routine 2 -- 33212
 Push Routine 1 -- 33322
 Finally 33332

因此:

pthread_exit(NULL).‘

  • 'Start 0’我们看到(如预期的)线程只会继续执行下去。

  • 'Start 1‘我们看到线程到达pthread_cleanup_pop(1); // (4),但是push_routine_4()没有通过printf()

我相信这表明一旦printf()完成了取消过程就开始了.

  • 'Start 2‘我们看到push_routine_4()printf(" Continue %u\n", step)之后调用,在后面的step++之前调用。

我相信这表明一旦printf(" Continue ...)完成了取消过程就开始了.

在我的机器上,Linux5.6.8运行glibc2.3,在函数完成后,printf()似乎是一个“取消点”。您得到的效果表明,在打印任何内容之前,printf()可能是一个“取消点”?或者,printf()push_routine_4()中不产生任何输出还有其他原因。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61867053

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档