线程相关及需要注意的地方

1.创建thread.

int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr,
              void *(*start_routine)(void*), void *restrict arg);

 

参数1:pthread_t *restrict thread:创建thread的thread ID.

参数2:const pthread_attr_t *restrict attr:创建线程的属性。

参数3:void *(*start_routine)(void*):thread服务程序。

参数4:void *restrict arg:thread服务程序参数。

 

2. 等待目标线程终止:

pthread_join() 函数会一直阻塞调用线程,直到指定的线程终止。

指定的线程必须位于当前的进程中,而且不得是分离线程。所有创建时属性为PTHREAD_CREATE_JOINABLE的非分离thread. 最终都需要调用pthread_join() or pthread_detach() 。这样thread所占资源和 Thread ID 才被释放。

 

3. 分离thread:

int pthread_detach(pthread_t thread);

pthread_detach()指出当thread 结束时,thread所占资源和Thread ID会被释放和再利用。如果调用pthread_detach()时,thread没有结束,它并不会导致thread退出。它只对PTHREAD_CREATE_JOINABLE 非分离thread有效。

 

4. 获取thread ID:

pthread_t pthread_self(void);

返回调用thread的thread ID.

 

5. 比较thread ID:

int pthread_equal(pthread_t t1, pthread_t t2);如果 tid1 和 tid2 相等,pthread_equal() 将返回非零值,否则将返回

 

6. 向thread发信号:

int pthread_kill(pthread_t thread, int sig);

tid 所指定的线程必须与调用线程在同一个进程中。sig 参数必须来自 signal(5) 提供的列表。

 

7. 退出线程:

void pthread_exit(void *value_ptr);

pthread_exit()用来终止调用thread并置位value_ptr.这个值会交给pthread_join。

 

 

Thread的取消:

同一进程内,某个Thread可以向其它thread发送取消要求,要求目标thread退出运行。

取消请求的处理方式取决于目标线程的状态。状态由以下两个函数确定:pthread_setcancelstate() 和pthread_setcanceltype()

 pthread_setcancelstate() 启用或禁用线程取消功能。创建线程时,缺省情况下线程取消功能处于启用状态。

pthread_setcanceltype() 可以将取消类型设置为延迟或异步模式。创建线程时,缺省情况下会将取消类型设置为延迟模式。在延迟模式下,只能在取消点取消线程。在异步模式下,可以在执行过程中的任意一点取消线程。因此建议不使用异步模式。

 

执行取消操作存在一定的危险。大多数危险都与完全恢复不变量和释放共享资源有关。取消线程时一定要格外小心,否则可能会使互斥保留为锁定状态,从而导致死锁。或者,已取消的线程可能保留已分配的内存区域,但是系统无法识别这一部分内存,从而无法释放它。

 

如果创建thread时使用缺省设置,则thread可以被取消,并为异步方式,所以向某一thread发送pthread_cancel()后,并不保证什么时候目标thread会被取消。只有当目标thread运行至取消点时才会真正退出。

 

类似Read,write等阻塞函数可以被看作取消点,但Sam记得并不能保证。所以建议使用手动添加取消点

pthread_testcancel();

当线程取消功能处于启用状态且取消类型设置为延迟模式时,pthread_testcancel() 函数有效。如果在取消功能处于禁用状态下调用 pthread_testcancel(),则该函数不起作用。

请务必仅在线程取消操作安全的序列中插入 pthread_testcancel()

例如:Sam一直以为poll()函数这样的阻赛类函数为cancel点,但其实不是,需要手动添加cancel点。

 

 

 

 几个误区及注意点:

 误区1: 分离线程不能被cancel.

这是将pthread_join与pthread_cancel搞混了。

thread分离可以在创建时设定,也可以用pthread_detach()在创建后设定。

被设定成分离线程后,表明它在退出thread时会自动回收资源。所以不需要pthread_join. 但分离thread完全可以接收pthread_cancel()来退出。

 

误区2:已经退出的thread,再去对它pthread_cancel()会出错。

不会出错,如果某thread已经退出,再向它发送pthread_cancel().不会出错。但会返回ESRCH。此值为3。

 ESRCH  No thread could be found corresponding to that specified by the given thread ID.

 

这里显示出:一个thread,不管自身return或pthread_exit(). 此thread都算停掉了。只是不分离thread需要使用pthread_join来回收资源而已。

 

 

注意点1:不管是否分离,主thread先于其它thread退出,都是不可控的。也就是说会不可预知错误。

所以,主thread不要使用return,exit等退出。 而是使用pthread_exit().

主thread使用pthread_exit(). 则会阻赛之,直到所有子thread退出后才退出。

 

 

推荐的做法:

常常有这样的需求,一个子thread既需要在某些事件发生时自己退出,也可能被主thread要求退出。

则可以做如下设计:

子thread自己退出时,使用pthread_exit().

其它thread要求它退出时,是用pthread_cancel(). pthread_join().

 

则当其它thread先要求它退出时,走正常途径,pthread_cancel()导致其退出。pthread_join()确保其退出并回收资源。

当其自动使用pthread_exit()退出时,最终主thread也会调用pthread_cancel(),则返回错误。但pthread_join()则确保回收资源。

 

 

pthread系列函数错误码:

大多数系统函数执行正确返回0。否则返回-1。错误码在errno中。所以可以使用perror()来显示错误。

但pthread系列函数却通过返回值传递error code. 并不向errno中写入错误码。所以不能使用perror()来查看错误原因。

 

可以使用strerror(pthread_rel) 来打印错误原因:

 

iRel_pthread = pthread_create(&mRtid, NULL, thread_Read_Data, this);
if(iRel_pthread != 0)
{
  std::cout <<"kDriver: Create Scan_Device thread Error." << strerror(iRel_pthread)  <<std::endl;
 }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值