Linux并发(异步信号)
Linux下的信号是诸多进程间通信(IPC)中唯一一种异步通信方式,这决定了信号的处理跟其他的IPC有本质差别。 拓展:一般情况下,进程什么时候会收到信号、收到什么信号是无法事先预料的(除了某几个特殊的信号之外),信号的到来就像你家门铃的响起一样,你不知道他什么时候会响。下图展示了内核中跟信号相关的最重要的数据组织关系:对这幅图的理解提几点重要说明:
Linux下的信号是诸多进程间通信(IPC)中唯一一种异步通信方式,这决定了信号的处理跟其他的IPC有本质差别。
拓展:
一般情况下,进程什么时候会收到信号、收到什么信号是无法事先预料的(除了某几个特殊的信号之外),信号的到来就像你家门铃的响起一样,你不知道他什么时候会响。
下图展示了内核中跟信号相关的最重要的数据组织关系:
对这幅图的理解提几点重要说明:
1,每一个线程都使用一个PCB(即task_struct)来表示,因此pending(不是指针)就是一个线程单独私有的,当我们使用pthread_kill( )给一个指定的线程发送某信号时,这些信号将会被存储在这个链队列中。
2,signal是一个指向线程共享的信号挂起队列相关结构体的指针,实际上,一个线程组(即一个进程)中的所有线程中的signal指针都指向同一个结构体,当我们使用诸如kill( )来给一个进程发送某信号的时候,这些信号将会被存储在shared_pending这个线程共享的链队列中。
如果一个进程中有超过1条线程,那么这些共享的挂起信号将会被随机的某条线程响应,为了能确保让一个指定的线程响应来自进程之外的、发送给整个进程的某信号,一般的做法如下:
除了指定要响应某信号的线程外,其他线程对这些信号设置阻塞。即使用sigprocmask( )或者pthread_sigmask( )将这些需要阻塞的信号添加到信号阻塞掩码blocked当中。
3,sighand也是一个指针,因此也是进程中的所有线程共享的,他指向跟信号响应函数相关的数据结构,结构体struct sighand_struct{}中的数组action有64个元素,一一对应LINUX系统支持的64个信号(其中0号信号是测试用的,32号和33号信号保留),每一个元素是一个sigaction{}结构体,其成员就是标准C库函数sigaction( )中的第二个参数的成员,可见,该函数相当于是一个应用层给内核设置信号响应策略的窗口。
另外,在编写信号响应函数时也应非常慎重地访问进程的共享数据,必要时要加锁来保护。响应函数跟进程的其他部分函数微观上虽然是串行执行的关系,但由于信号触发点的异步特性,就使得信号响应函数的执行跟进程的其他部分函数在宏观上是并行执行关系,请看图解:
可以看到,由于信号触发点可以发生在进程执行过程中的任意时刻,因此响应函数f( )事实上就是跟主进程并发的,在响应函数内部访问任何共享资源,都必须跟多线程一样,使用同步互斥机制来确保访问的安全性。
更多推荐
所有评论(0)