进程通信(2)
信号
信号本质:信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断信号是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道到底什么时候到达。
信号来源:信号事件发生有两个来源,硬件来源(比如按下键盘或其他硬件故障);软件来源,最常用发生信号的系统函数是kill,raise,alarm,setitimer及sigqueue函数,软件来源还包括一些非法运算等操作。
分类:
(1)从可靠性方面,分为可靠信号与不可靠信号
(2)从时间方面,可分为实时信号与非实时信号
可靠性信号与不可靠信号
1.不可靠信号:(信号值小于SIGRTMIN)早期的Unix系统中信号机制比较简单和原始,将那些建立在早期机制上的信号称为不可靠信号,信号可能会丢失
2.可靠信号:(信号值介于SIGRTMIN, SIGRTMAX之间)新增了一些信号,这些信号在定义时就定义为可靠信号,这些信号支持排队,不会丢失
信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数有关
实时信号与非实时信号:
早期Unix系统之定义了32种信号,Red Hat 7.2支持64种信号,编号为0—63,前32种信号已经有了预定义值,每个信号有了确定的用途及含义,并且每种信号都有各自的默认动作。
后32种信号表示实时信号,等同于前面阐述的可靠信号,这保证额发送的多个实时信号都被接受。实时信号是POSIX标准的一部分,可用于应用进
程。
非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号;
信号的处理方式:
1.忽略信号:对信号不作处理,其中,有两个信号不能忽略,即SIGKILL和SIGSTOP
2.捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数
3.执行默认操作:Linux对每种信号都规定了默认操作,注意,进程对实时信号的默认反应是进程终止
信号发送
发生信号的主要函数有:
kill(),raise(),sigqueue(),alarm(),setitimer()和abort()。
1.kill()函数
kill函数用于传送信号给指定的进程
int kill(pid_t pid , int sig);
参数说明:
- pid > 0 :将信号传给进程识别码为pid的进程
- pid = 0:将信号传给和目前进程相同进程组的所有进程
- pid = -1:将信号广播传送给系统内所有的进程
- pid < 0:将信号传给进程组识别码为pid绝对值的所有进程
返回值:执行成功则返回0,如果有错误则返回-1;
2.alarm()函数
alarm函数用于设置信号传送闹钟
unsigned int alarm(unsigned int seconds);
参数说明:
alarm()用来设置信号SIGALRM,在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。
返回值:
返回之前闹钟剩余的秒数,如果之前未设置闹钟则返回0;
自定义处理信号方式
Linux主要由两个函数来实现信号的安装——signal()和sigaction()。其中,signal()是在可靠信号系统调用的基础上实现的,是库函数,只有两个参数,不支持信号传递信息,主要是用于前32种非实时信号的安装;而sigaction()是较新的函数,有三个参数,支持信号传递信息,主要用来与sigqueue系统调用配合使用,当然sigaction()同样支持非实时信号的安装。
1.signal函数
signal函数用来传送给指定的进程
void(*signal(int signum, void(*handler)(int)))(int);
函数说明:
signal()会议参数signum指定的信号来设置还信号的处理函数,当指定的信号到达时就会跳转到参数handler指定的函数执行;
如果参数handler不是函数指针,则必须是下列两个常量之一:
1.SIG_IGN:忽略参数signum指定的信号
2.SIG_DFL:将参数signum指定的信号重设为核心预设的信号处理方式
返回值:
返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)
2.sigaction函数
sigaction函数用来查询或设置信号处理方式
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数说明:
sigaction()会以参数signum指定的信号的编号来设置该信号的处理函数,参数signum可以指定除SIGKILL和SIGSTOP以外的所有信号,如果参数结构sigaction定义如下:
struct sigaction
{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flag;
void (*sa_restorer)(void);
};
消息队列
管道只能传送无格式字节流,能够传送的信号量有限,消息队列(也称为报文队列)则克服了 这些缺点。
消息队列是一个消息的链表,可以把消息看作是一个记录,具有特定的格式。
消息队列的执行步骤大致如下:
1.打开、创建
2.发送信息
3.接受信息
4删除消息队列
下面,我们