第十章第七节 多线程环境
可重入函数
Linux库函数只有一小部分是不可重入的,但Linux为其提供了对应的可重入版本,这些可重入版本的函数在原函数名尾部加_r;在多线程程序中调用库函数,必须使用其可重入版本。
fork与互斥锁
考虑下面情况:一个多线程程序的某个线程调用了fork函数,则子进程仅拥有一个执行线程,即调用fork的线程的完整复制,且子进程将自动继承父进程中互斥锁、POSIX信号量、条件变量的状态。即,父进程中被加锁的互斥锁在子进程中也是锁住的,但子进程并不清楚该互斥锁的状态,此时如果再次加锁,就会导致死锁。
为此,pthread专门提供了pthread_atfork函数以确保fork调用后父进程与子进程都清楚锁的状态。
1 | /* |
线程与信号
在多线程下应用程序应使用pthread版本的sigprocmask函数——pthread_sigmask。
1 | /* |
函数的参数含义与sigprocmask的参数含义相同。
由于进程中所有线程共享进程的信号,因此线程库将根据线程掩码决定将信号发送到哪个具体的线程,但如果在每个子进程中都单独设置信号掩码,则很容易导致逻辑错误;此外,所有线程共享信号处理函数,当一个线程设置了某个信号的信号处理函数后,它将覆盖其他线程为同一信号设置的信号处理函数。
综上,应用程序应该定义一个专门的线程处理所有的信号。实现步骤如下。
- 在主线程创建出其他子线程之前就调用pthread_sigmask来设置好信号掩码,所有新创建的子线程都将自动继承这个信号掩码;从而所有的线程都不会响应被屏蔽的信号;
- 在某个线程中调用sigwait函数来等待信号并处理它;
1 | /* |
若sigwait正确返回,应用程序可对接收的信号作出处理;此时,应用程序无需再为信号设置信号处理函数。
最后,pthread提供了pthread_kill函数以将一个信号明确地发送给指定线程。
1 | /* |