免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2166 | 回复: 9
打印 上一主题 下一主题

[C] 这个例子 pthread_cleanup_pop(0) 没用? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-03-07 13:16 |只看该作者 |倒序浏览
从输出的信息可知 pthread_cleanup_pop(0); 并没有执行啊~~~~`
  1. #include <stdio.h>
  2. #include <pthread.h>

  3. pthread_mutex_t                  mutex;
  4. pthread_cond_t                  cond;

  5. void cleanup(void *arg)
  6. {
  7.         pthread_mutex_unlock(&mutex); //unlock
  8.         return;
  9. }  

  10. static void  ThreadFun(void)
  11. {
  12.         pthread_cleanup_push(cleanup,NULL);

  13.         while(1)
  14.         {
  15.                   pthread_mutex_lock(&mutex); //lock
  16.                   pthread_cond_wait(&cond,&mutex);
  17.                   pthread_mutex_unlock(&mutex); //unlock
  18.         }

  19.         printf("1 return ThreadFun\n");
  20.        
  21.         pthread_cleanup_pop(0);

  22.         printf("2 return ThreadFun\n");

  23.         return;
  24. }

  25. void main()
  26. {
  27.         int i;
  28.         pthread_t    tid[10];  

  29.         pthread_mutex_init(&mutex, NULL);
  30.         pthread_cond_init(&cond,NULL);

  31.         for(i = 0; i < 10; i++)
  32.                   pthread_create(&tid[i], NULL, (void *)ThreadFun ,NULL);


  33.         for(i = 0; i < 10; i++)
  34.         {
  35.                 pthread_cancel(tid[i]);
  36.                 pthread_join(tid[i],NULL);
  37.         }

  38.         pthread_mutex_destroy(&mutex);
  39.         pthread_cond_destroy(&cond);
  40.        
  41.         printf("main return\n");

  42.         return;
  43. }
复制代码
输出:

main return

没有输出 “1 return ThreadFun” 和 "2 return ThreadFun" ,说明 pthread_cleanup_pop(0) 没有执行,有什么问题?

论坛徽章:
0
2 [报告]
发表于 2013-03-07 14:25 |只看该作者
本帖最后由 timothyqiu 于 2013-03-07 14:26 编辑

没什么问题,没输出是因为你 cancel 了呀~ cancel 了就直接执行 cleanup 然后退出线程,不会再往下执行了。

论坛徽章:
0
3 [报告]
发表于 2013-03-07 14:29 |只看该作者
timothyqiu 发表于 2013-03-07 14:25
没什么问题,没输出是因为你 cancel 了呀~ cancel 了就直接执行 cleanup 然后退出线程,不会再往下执行了。 ...


这个知道,我问的是没执行 pthread_cleanup_pop(0) 会不会有资源没释放什么的?

论坛徽章:
0
4 [报告]
发表于 2013-03-07 14:39 |只看该作者
回复 3# iw1210

man pthread_cleanup_pop

The pthread_cleanup_pop() function removes the routine at the top of the stack of clean-up handlers, and optionally executes it if execute is nonzero.

A cancellation clean-up handler is popped from the stack and executed in the following circumstances:

1. When a thread is canceled, all of thr stacked clean-up handers are poped and executed in the reverse of the order in which they are pushed onto the stack.
2. When a thread terminates by calling pthread_exit(3), all clean-up handlers are executed as described in the preceding point.
3. When a thread calls pthread_cleanup_pop() with a nonzero excute argument, the top-most clean-up handler is popped and executed.

总而言之,调用一次就弹栈一次。如果是线程被 cancel, exit 终止就依次弹光,运行光。

所以不会泄漏的……

论坛徽章:
0
5 [报告]
发表于 2013-03-07 14:58 |只看该作者
timothyqiu 发表于 2013-03-07 14:39
回复 3# iw1210

man pthread_cleanup_pop


没看到调用pop,什么时候弹的?

论坛徽章:
0
6 [报告]
发表于 2013-03-07 22:55 |只看该作者
本帖最后由 timothyqiu 于 2013-03-07 23:10 编辑

回复 5# iw1210

你得搞清 pthread_cleanup_pop() 是干什么的呀。

pthread_cleanup_push 是把函数压进 cleanup 栈里;pthread_cleanup_pop 是把函数弹出,如果参数不为 0 还会执行一下被弹出的函数。

pthread_cleanup_pop(0); 实际上只是从 cleanup 栈里把之前压进去的函数弹掉而已。

---

不考虑 while 循环,你的 ThreadFun 里是这样的:

{
    1. pthread_cleanup_push(cleanup, NULL); 把 cleanup 函数压进 cleanup 栈。
    2. 业务逻辑处理中……
    3. pthread_cleanup_pop(0); 把 cleanup 栈栈顶的函数(也就是 cleanup 函数)弹出来,不调用。
}

在被 cancel 的情况下:

{
    1. pthread_cleanup_push(cleanup, NULL); 把 cleanup 函数压进 cleanup 栈。
    2. 业务逻辑处理被中断,跳到 4
    4. pthread 内部逻辑:把 cleanup 栈依次弹出,并调用被弹出的函数。(结果是 cleanup 栈空了,cleanup 函数被调用)
}

所以不考虑具体实现的话,其实是可以不写 pthread_cleanup_pop(0); 的。(实际上不行,因为这俩函数可能是必须成对出现的宏。)

论坛徽章:
0
7 [报告]
发表于 2013-03-08 09:10 |只看该作者
回复 6# timothyqiu


   看你说的意思,好象是每次调用cleanup,都背后自动pop了一次?

论坛徽章:
6
申猴
日期:2013-10-08 17:32:32金牛座
日期:2013-10-18 19:45:53天秤座
日期:2013-10-18 20:17:34处女座
日期:2014-02-11 10:10:29丑牛
日期:2014-02-15 10:44:15巳蛇
日期:2014-02-18 22:05:54
8 [报告]
发表于 2013-03-08 13:31 |只看该作者
这些线程执行该语句时 pthread_cond_wait(&cond,&mutex);进行了阻塞,等待被唤醒,当执行pthread_cancel函数,由于pthread_cond_wait属于取消点,线程退出,并且pthread_cleanup_push函数进行了压栈操作,线程退出时进行出栈操作

论坛徽章:
6
申猴
日期:2013-10-08 17:32:32金牛座
日期:2013-10-18 19:45:53天秤座
日期:2013-10-18 20:17:34处女座
日期:2014-02-11 10:10:29丑牛
日期:2014-02-15 10:44:15巳蛇
日期:2014-02-18 22:05:54
9 [报告]
发表于 2013-03-08 13:45 |只看该作者
回复 8# helpstudy
在该程序中,pthread_cleanup_pop(0)语句不会被执行,仅用于与pthread_cleanup_push函数进行配对,否则编译出错,由于执行pthread_cancel时已经对栈进行了出栈处理,执行到取消点函数时线程已退出,后面的语句不会被执行

   

论坛徽章:
0
10 [报告]
发表于 2013-03-08 23:29 |只看该作者
回复 7# iw1210

这不是我的说法,是 man 的说法。


//////////////////////////
编程不是自然科学,研究的领域不是未知的,不需要自己猜测或者探索某个函数的运行规律。看手册就全知道了。

究竟弹没弹、什么时候弹、什么时候不弹,直接在命令行里敲 man pthread_cleanup_pop 就全知道了,你问别人,别人也是从那里拿来的信息。

//////////////////////////
但编程是科学,究竟行不行、是不是,自己实验一下就知道了。

最不济,打开 /usr/include/pthread.h 看看:
  1. #  define pthread_cleanup_push(routine, arg) \
  2.    do {                                      \
  3.      __pthread_cleanup_class __clframe(routine, arg)

  4. #  define pthread_cleanup_pop(execute)  \
  5.      __clframe.__setdoit(execute);      \
  6.    } while (0)
复制代码
宏定义展开总会吧?
  1. pthread_cleanup_push(cleanup, NULL);
  2. ...
  3. pthread_cleanup_pop(0);
复制代码
变成:
  1. do {
  2.     __pthread_cleanup_class __clframe(routine, arg);
  3.     ...
  4.     __clframe.__setdoit(execute);
  5. } while(0);
复制代码
可见一次调用实质上只增加了一个 __clframe 这个对象,而这个对象是在栈上的。那么你担心的「直接中断退出会不会造成资源泄漏」也只可能是因为 __pthread_cleanup_class 类内部有资源没有释放吧。

那么我们再看上面的 __pthread_cleanup_class 类:
  1. class __pthread_cleanup_class
  2. {
  3.   void (*__cancel_routine) (void *);
  4.   void *__cancel_arg;
  5.   int __do_it;
  6.   int __cancel_type;

  7. public:
  8.   __pthread_cleanup_class (void (*__fct) (void *), void *__arg)
  9.     : __cancel_routine (__fct), __cancel_arg (__arg), __do_it (1) { }
  10.   ~__pthread_cleanup_class () { if (__do_it) __cancel_routine (__cancel_arg); }
  11.   void __setdoit (int __newval) { __do_it = __newval; }
  12.   void __defer () { pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED,
  13.                        &__cancel_type); }
  14.   void __restore () const { pthread_setcanceltype (__cancel_type, 0); }
  15. };
复制代码
究竟可不可能泄漏、什么情况下可能泄漏就很明显了。

当然看具体实现只是没办法的办法,实现不一定遵循标准。所以还是看 man 来得划算。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP