Linux多线程学习笔记(3)-线程的基本控制

Linux多线程学习笔记(3)-线程的基本控制

1 线程终止

1.1 exit是危险的

如果进程中的任意一个线程调用了exit,_Exit,_exit,那么整个进程就会终止。

1.2 不终止进程的退出方式

普通的单个线程有以下三种方式退出,这样不会终止进程
① 从启动例程中返回,返回值是线程的退出码
② 线程可以被同一进程中的其他线程取消
③ 线程调用pthread_exit(void *rval)函数,rval是退出码

2 线程连接与分离

2.1 线程连接

有时候我们在一个线程中创建了另外一个线程,主线程要等到创建的线程返回了,获取该线程的返回值后主线程才退出。这个时候就需要用到线程连接。

int pthread_join(pthread_t tid, void **rval)

• 调用该函数的线程会一直阻塞,直到指定的线程tid调用pthread_exit、从启动例程返回或者被取消
• 参数tid就是指定程的id
• 参数rval是指定线程的返回码,如果线程被取消,那么rval被置为 PTHREAD _CANCELED
• 该数调用成功会返回0,失败返回错误码
• 调用pthread_join会使指定的线程处于分离状态,如果指定线程已经处于分离状态,那么调用就会失败
• 当pthread_join返回以后,其他的线程就不能调用pthread_join连接id指定的程了

2.2 线程分离

int pthread_detach(pthread_t thread)

• pthread_detach可以分离一个线程,线程可以自己分离自己
• 成功返回0,失败返回错误码

3 线程取消

3.1 取消函数

int pthread_cancel(pthread_t tid)

取消tid指定的线程,成功返回0。但是取消只是发送一个请求,并不意味着等待线程终止,而且发送成功也不意味着tid一定会终止

3.2 取消状态

取消状态,就是线程对取消信号的处理方式,忽略或者响应。线程创建时默认响应取消信号。

int pthread_setcancelstate(int state, int *oldstate)

设置本线程对Cancel信号的反应,state有两种值:PTHREAD_ CANCEL_ ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
分别表示收到信号后设为 CANCLED状态和忽略 CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。

3.3 取消类型

取消类型,是线程对取消信号的响应方式,立即取消或者延时取消。线程创建时默认延时取消。

int pthread_setcanceltype(int type, int *oldtype)

设置本线程取消动作的执行时机,type由两种取值:PTHREAD_ CANCEL_ DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为 Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入原来的取消动作类型值。

3.4 取消点

取消一个线程,它通常需要被取消线程的配合。线程在很多时候会查看自己是否有取消请求。如果有就主动退出,这些查看是否有取消的地方称为取消点。
很多地方都是包含取消点,包括pthread_join(), pthread_testcancel(), pthread_cond_wait(), pthread_cond_timedwait(),sem_wait(),sigwait(),write,read等。大多数会阻塞的系统调用。
可以通过man pthreads查看。

4 向线程发送信号

4.1 pthread_kill

int pthread_kill(pthread_t thread, int sig)

① 别被名字吓到,pthread_kill可不是kill,而是向线程发送signal。大部分 signal的默认动作是终止进程的运行,所以,我们才要用sigaction()去抓信号并加上处理函数。
② 向指定ID的线程发送sig信号,如果线程代码内不做处理,则按照信号默认的行为影响整个进程。也就是说,如果你给一个线程发送了SIGQUIT,但线程却没有实现signal处理函数,则整个进程退出。
③ 如果要获得正确的行为,就需要在线程内实现sigaction了。
④ 所以,如果int sig的参数不是0,那一定要清除是到底要干什么,而且一定要实现线程的信号处理函数,否则,就会影响整个进程。
⑤ 如果int sig是0,这是一个保留信号,其实并没有发送信号,作用是用来判断线程是不是还活着。

4.2 信号处理

① 进程信号处理:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)

给信号 signum设一个处理的函数,处理函数在sigaction中指定
act. sa_mask 信号屏蔽字
act. sa_handler 信号集处理程序

int sigemptyset(sigset_t *set);清空信号集
int sigfillset(sigset_t *set);将所有信号加入信号集
int sigaddset(sigset_t *set, int signum);增加一个信号到信号集
int sigdelset(sigset_t *set, int signum); 删除一个信号到信号集

② 多线程信号屏蔽处理

int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)

how= SIG_BLOCK:向当前的信号掩码中添加set,其中set表示要阻塞的信号组。SIG_UNBLOCK:向当前的信号掩码中删除set,其中set表示要取消阻塞的信号组。
SIG_SETMASK:将当前的信号掩码替换为set,其中set表示新的信号掩码
在多线程中,新线程的当前信号掩码会继承创造它的那个线程的信号掩码
一般情况下,被阻塞的信号将不能中断此线程的执行,除非此信号的产生是因为程序运行出错如SIGSEGV;另外不能被忽略处理的信号SIGKILL和SIGSTOP也无法被阻塞。
注意:对信号的处理以最后一次调用sigaction为准

5 清除操作

线程可以安排它退出时的清理操作,这与进程的可以用atexit函数安排进程退出时需要调用的数类似。
这样的函数称为线程清除处理程序。线程可以建立多个清理处理程序,处理程序记录在栈中,所以这些处理程序执行的顺序与他们注册的顺序相反。

pthread_cleanup_push(void(*rtn)(void*),void *args)//注册处理程序
pthread_cleanup_pop(int excute)//清除处理程序

这两个函数要成对的出现,否则编译无法通过
当执行以下操作时调用清理函数,清理函数的参数由args传入
① 调用pthread_exit
② 响应取消请求
③ 用非零参数调用pthread_cleanup_pop

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值