Linux编程——终止线程的正常方式及取消点

问题背景:
在使用pthread_cancel和pthread_join退出一个线程时,线程本身会立即停止运行代码并退出吗?如果在你试图退出一个线程时,该线程中还有未释放的资源,这时应该怎么处理呢?

在cancel一个线程时,线程体可能并不会立即退出,这就会出现两个问题:

  1. 在调用cancel之后,如果线程体仍在运行,就会导致pthread_join()阻塞,进而使调用pthread_join()的线程也被阻塞。当然你也可以用pthread_detach(),但这种让线程自生自灭的方式可能导致一些不可控的情况。
  2. 如果在线程退出时有动态分配的内存未释放,则会产生内存泄漏,如果有锁还没有释放则其他地方就一直拿不到锁了从而导致死锁。

这两个问题,我们都可以利用线程的取消点(cancellation points)来避免。线程的cancel type有两种:PTHREAD_CANCEL_DEFERRED和PTHREAD_CANCEL_ASYNCHRONOUS,前者为默认类型,意味着线程只有在取消点处才能被cancel。也就是说,在对线程pthread_cancel()之后,线程还要继续执行到下一个取消点才会退出。
可以通过pthread_setcanceltype()来改变线程的cancel type,但强烈不建议这样做,因为你如果改为PTHREAD_CANCEL_ASYNCHRONOUS类型,线程可以在代码的任何地方退出,就很难处理上述两个资源释放问题。

所谓“取消点”就是一个函数,例如sleep(),当线程体运行到sleep()的时候,就可以响应cancel了。这样一来,我们可以这样做:

  1. 在代码的适当位置主动插入取消点,主要为了防止耗时操作(例如比较大的while循环)导致线程无法退出。
  2. 在需要进行同步操作时不设置取消点,例如在加锁和解锁之间、线程内存申请的内存free之前,或者你代码逻辑中必须做完某事才能退出的。这样你就不用担心线程退出前还有未达成的遗愿。

除了通过设置取消点的方式来控制线程退出之外,还有一对函数:pthread_cleanup_push() /pthread_cleanup_pop(),可以让你单独注册一个清理函数。但这种方式没有取消点来的简单,因为在线程不同地方要做的清理可能也不相同。

不过,我的建议是,尽量创建常驻线程,让它一直存在,没事做就等着,省了在取消点上伤脑筋。
更多多线程的编程指南,可参考https://docs.oracle.com/cd/E19455-01/806-5257/index.html

至于哪些函数可作为取消点,大家可参考 https://linux.die.net/man/7/pthreads 中的Cancellation points一节。

下面转载的两篇文章介绍了如何选择取消点(cancellation points)以及如何清理线程资源,原文分别为:
https://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part4/
http://blog.csdn.net/shi

  • 8
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值