操作系统进程间通信方式,系统中进程间通信
进程间通信-信号信号什么是信号?Signal为程序提供了处理异步事件的方法,通过软件中断来实现。
我们不能定制信号,所有信号都是由系统预先定义的。
谁发出的信号?显示当前错误(例如,段错误、非法指令等。),shell终端通过Ctrl C生成相应的信号,比如socket通信或者pipeline通信,如果阅读器关闭,那么写(或者发送数据)就会导致执行写的进程收到SIGPIPE信号(表示管道断了)。
信号——的默认行为终止该过程。
在shell终端,使用kill或killall命令生成信号。示例:
Kill -HUP pid #向pid为pid的进程发送SIGHUP signal #include stdio.h
#包含stdlib.h
#包含信号. h
void myhandle(int sig) {
printf(捕捉信号:%d\n ,SIG);
}
int main(void) {
//设置信号处理功能
signal(SIGINT,my handle);//如果收到SIGINT信号,执行myhandle。如果没有设置信号处理功能,则执行默认处理3354并终止。
while (1) {
睡眠(1);
}
返回0;
}调用代码中的kill函数生成信号——。详见-kill()函数UNIX/Linux Intkill (PID _ T PID,int SIG);//进程pid,信号类型的信号有哪些?信号名称描述
SIGABORT——进程异常终止。
Sigurm——超时警报
sige——浮点运算异常
Sighup3354连接挂起。
SIGILL——非法指令
Sig——终端中断(Ctrl C将生成此信号)
Sig—— *终止进程
SIGPIPE ——在没有读取过程的情况下将数据写入管道。
SIGQUIT——终端退出(Ctrl \将生成此信号)
Segv——无效的内存段访问
SIGTERM ——已终止
Sig1—— *用户定义信号1
SIGUSR2 ——*用户定义信号2
-如果没有捕捉到上述信号,则在接收到这些信号后,进程将被终止!
SIGCHLD——子进程已停止或退出。
Sigcont3354 *让暂停的进程继续。
Stop —— *停止执行(即“暂停”)
SIGTSTP——关闭保持
Siggin——守护程序试图读取。
SIGTTOU——守护程序试图写入。
信号处理忽略该信号。捕捉信号并指定信号处理功能进行处理。详见安装信号执行系统默认动作,大部分是终止进程。信号捕获(Signal capture)信号捕获是指接收到某个信号后,执行指定的功能。
注意:
SIGKILL和SIGSTOP信号不能被捕获,即这两个信号对应的动作不能改变。安装信号sighandler _ tsignal (int signum,sighandler _ t signal);其中:信号函数的返回类型和第二个参数都是函数指针类型。在第二个参数中:有以下两个特殊值。SIG_IGN——忽略信号SIG_DFL——恢复默认行为示例:
signal(SIGINT,my handle);//myhandle是自定义信号处理函数SIGATION。与信号相比,信号更加鲁棒。
结构信号作用:
结构信号动作{
//信号的响应函数
void(* sa _ handler)(int);
//省略.
void (*sa_sigaction)(int,siginfo_t *,void *);
//搁置信号集
sigset _ t sa _ mask
//当sa_flags中包含SA_RESETHAND时,接收到信号并调用指定的信号处理函数执行后,信号的响应行为被重置为默认行为SIG_DFL。
//即用户自定义的信号处理函数执行一次后,会回到默认的处理模式。
int sa _ flags
//省略.
void(* sa _ restorer)(void);
};补充:
当sa_mask包含某个信号A时,如果信号A发生在信号处理函数执行过程中,信号A将被阻塞,即暂时不响应信号,然后响应信号A,直到信号处理函数执行完毕。函数sigaction:
int sigaction(int signum,
const struct sigaction *act,
Struct sigaction *oldact//保存旧设置
);1:使用示例
#包含stdio.h
#包含stdlib.h
#包含信号. h
void myhandle(int sig) {
printf(捕捉信号:%d\n ,SIG);
}
int main(void) {
结构信号作用法;
act.sa _ handler=myhandle
sigemptyset(act . sa _ mask);//清空搁置集
act . sa _ flags=0;
sigaction(SIGINT,act,0);
while (1) {
睡眠(1);
printf(睡眠1秒。\ n’);
}
返回0;
}例2:输入A,主进程向子进程发送SIGUSR1信号,输出大写字符;一个输入主进程向子进程发送SIGUSR2信号,并输出小写字符。
#包含stdio.h
#包含stdlib.h
#包含信号. h
int work flag=0;
void work_up_handle(int sig) {
work flag=1;
}
void work_down_handle(int sig) {
work flag=0;
}
/*
似乎一个sigaction结构对象可以设置多对信号和信号处理函数。
即根据接收到的信号调用相应的信号处理函数。
*/
int main(void) {
pid _ t pd
char c;
PD=fork();
if (pd==-1) {
printf(fork错误!\ n’);
出口(1);
} else if (pd==0) {//子进程
char * msg
结构信号作用法;
act . sa _ flags=0;
act.sa _ handler=work _ up _ handle//结构设置信号处理函数。
sigemptyset(act . sa _ mask);
sigaction(SIGUSR1,act,0);
act . sa _ handler=work _ down _ handle;//结构设置信号处理函数。
sigaction(SIGUSR2,act,0);
while (1) {
如果(!工作标志){
msg=子流程工作!;
}否则{
msg=子流程工作!;
}
printf(%s\n ,msg);
睡眠(1);
}
} else {//父进程
while(1) {
c=getchar();
if (c==A) {
kill(pd,SIG usr 1);//向子进程pd发送信号SIGUSR1
} else if (c==a) {
kill(pd,SIG usr 2);//向子进程pd发送信号SIGUSR2
}
}
}
返回0;
}例3:利用子进程的定时向父进程发送SIGALRM信号。
#包含stdio.h
#包含stdlib.h
#包含信号. h
int wake flag=0;
void wake_handle(int sig) {
wake flag=1;
}
int main(void) {
pid _ t pd
char c;
PD=fork();
if (pd==-1) {
printf(fork错误!\ n’);
出口(1);
} else if (pd==0) {
for(;){
睡眠(5);
//getppid()获取父进程id
kill(getppid(),sigal RM);//向父进程发送SIGALRM信号
}
}否则{
结构信号作用法;
act.sa _ handler=wake _ handle
act . sa _ flags=0;
sigemptyset(act . sa _ mask);//空的
sigaction(SIGALRM,act,0);//设置信号响应
for(;){
pause();//暂停进程,直到收到任何信号。
if(唤醒标志){
printf(闹钟工作!\ n’);
}
}
}
返回0;
}
使用报警功能在指定时间内向过程本身发送信号。意思是调用这行代码后,你计时几秒后,SIGALRM信号发出。原型函数unsigned int alarm(unsigned int seconds);注:时间单位为“秒”。实际闹钟时间比指定时间稍长。如果参数为0,设置的闹钟将被取消。如果闹铃时间还没到,再叫一次闹铃,闹钟就会重置。每个进程最多只能使用一个闹钟。返回值:失败:返回-1。成功:返回最后一个闹钟的剩余时间(秒)。示例:# includesdio.h
#包含stdlib.h
#包含信号. h
#包含时间. h
int wake flag=0;
void wake_handle(int sig)
{
wake flag=1;
}
int main(void) {
int ret
结构信号作用法;
act . sa _ flags=0;
act.sa _ handler=wake _ handle//设置响应函数
sigemptyset(act . sa _ mask);
sigaction(SIGALRM,act,0);//设置信号响应
printf(time=%ld\n ,time((time _ t *)0));
ret=报警(5);
if (ret==-1) {
printf(报警错误!\ n’);
出口(1);
}
for(;){
//暂停当前进程,直到收到任何信号。
pause();
if(唤醒标志){
printf(唤醒,时间=%ld\n ,时间((time _ t *)0));
}
}
返回0;
}使用raise函数向进程本身发送指定的信号。通话后立即发送。Prototype: int raise (int sig)示例:省略。发送多个信号的前提:对应的信号已经绑定了对应的信号处理函数。详情参见信号处理。
当进程正在执行与信号对应的操作功能(即,对应信号的安装功能)时,该进程多次接收相同的信号(具有相同信号值的信号)。
注意:如果信号不可靠(值32),只能再响应一次。如果信号是可靠的信号(32),它可以多次响应(无遗漏)。但是你要等这个响应函数完成,才能响应下一个。
进程正在执行对应于信号的操作功能(信号的安装功能)。如果该过程此时接收到另一个信号(具有不同信号值的信号),则:
如果信号包含在当前信号的signaction的sa_mask(信号搁置集)中,则不会立即处理该信号。在执行完当前信号处理功能之前,它不会被执行。
相反,如果信号不在信号搁置集中,则当前的信号处理功能将被中断,如果处于睡眠中,如睡眠,则立即被唤醒执行新的信号处理功能。新的信号处理功能执行后,会回到原来的信号处理功能继续执行。
示例:
#包含stdio.h
#包含stdlib.h
#包含信号. h
void myhandle(int sig)
{
printf(捕捉信号:%d\n ,SIG);
int I;
for(I=0;i i ) {
睡眠(1);
}
printf(Catch end。%d\n ,签名);
}
int main(void)
{
struct sigaction act,act 2;
act.sa _ handler=myhandle
sigemptyset(act . sa _ mask);
sigaddset( act.sa_mask,sigus R1);//将信号SIGUSR1添加到信号搁置集。
act . sa _ flags=0;
sigaction(SIGINT,act,0);//处理SIGINT停止信号
//接收到SIGINT信号。如果此时再次接收到SIGURSR1,执行后将进行SIGURSR1信号处理。
act 2 . sa _ handler=my handle;
sigemptyset(act 2 . sa _ mask);
act 2 . sa _ flags=0;
sigaction(SIGUSR1,act,0);//处理SIGUSR1信号
while (1) {
}
返回0;
}以上详细解释:
首先接收SIGINT信号,如果此时接收到SIGUSR1,则SIGUSR1信号处理将在SIGINT信号处理功能完成后执行,因为SIGUSR1响应SIGINT信号被添加到信号搁置集。结果如下图所示:
首先接收SIGUSR1信号;如果此时再次接收到SIGINT,会先执行SIGINT的信号处理功能,然后继续执行SIGUSR1的信号处理功能。结果如下图所示:
Set sigset_t什么是信号集?示例:结构sigaction中的参数——sigset_t sa_mask,此sa_mask是信号搁置集。
用sigset_t类型表示,本质上是一种无符号长整型。用于表示包含多个信号的集合。信号集sigemptyset——的基本操作是清除信号集。Sigfillset——将所有定义的信号填充到指定的信号集中。从指定的信号集中删除指定的信号。Addsigset3354添加指定信号集中的指定信号。Sigismember——判断指定信号是否在指定信号集中。如果是,返回1。如果不是,则返回0。无效信号,返回-1。过程的“信号屏蔽”。什么是信号屏蔽?
进程的“信号掩码”是一个信号集。当向目标进程发送信号时,如果信号在目标进程的信号掩码中,目标进程将不会捕获该信号,即不会执行该信号的信号处理功能。当这个进程的信号屏蔽不再包含这个信号时,它将捕获这个已经接收到的信号(执行相应的信号处理功能)。如何修改一个进程的信号掩码?
使用sigprocmask函数的原型:int sigprocmask (int how,const sigset _ t * set,sigset _ t * old set);参数表:how: sig _ block3354将参数集中的信号添加到信号掩码字中。在原来的基础上增加。SIG_UNBLOCK——从信号屏蔽中删除参数集中的信号。在现有的基础上删除。SIG_SETMASK——将参数集中的信号设置为信号屏蔽字。原来的不生效,新加的生效。Oldset:返回在set之前设置的原始信号掩码,即原始(之前设置的)信号掩码。示例:# includesdio.h
#包含stdlib.h
#包含信号. h
void myhandle(int sig) {
printf(捕捉信号:%d\n ,SIG);
printf(Catch end。%d\n ,签名);
}
int main(void) {
struct sigaction act,act 2;
act.sa _ handler=myhandle
sigemptyset(act . sa _ mask);
act . sa _ flags=0;
sigaction(SIGINT,act,0);
sigset _ t proc _ sig _ msk//当前信号掩码字
sigset _ t old _ mask//旧信号掩码字
sigemptyset(proc _ SIG _ MSK);//清除信号集
sigaddset( proc_sig_msk,SIGINT);//将信号添加到信号掩码集中
sigprocmask(SIG_BLOCK,proc_sig_msk,old _ mask);//以增量方式修改进程的信号掩码。
睡眠(5);
printf( had delete SIGINT from process SIG mask \ n );
sigprocmask(SIG_UNBLOCK,proc_sig_msk,old _ mask);//删除proc_sig_msk中的信号
while (1) {
}
返回0;
}获取未处理的信号当接收到信号掩码中的信号时,这些信号不会被这个进程响应。这些未处理的信号可以通过sigpending函数获得。prototype:intsighppending(sigset _ t * set);返回值:成功:返回0。失败:返回-1。阻塞等待信号pausepause——阻塞该进程,直到它在接收到任何信号后被解除阻塞。使用:暂停()。注意:这里提到的任何信号都不能在这个进程的信号掩码集中。另外需要注意的是,如果信号没有被屏蔽和捕获(安装——在即将到来的过程中安装相应的信号绑定信号处理功能。),接收到一些信号后,进程就会终止。具体看上面有哪些信号。Sigsuspendsigsuspend——用指定的参数替换当前进程的掩码字。当接收到这个信号时,掩码字中的信号无效,即被阻塞。接收到信号屏蔽字以外的信号后,解除屏蔽,并做出相应的响应。注意,具体响应内容与上面暂停中的相同。示例:# includesdio.h
#包含stdlib.h
#包含信号. h
void myhandle(int sig) {
printf(捕捉信号:%d\n ,SIG);
printf(Catch end。%d\n ,签名);
}
int main(void) {
struct sigaction act,act 2;
act.sa _ handler=myhandle
sigemptyset(act . sa _ mask);
act . sa _ flags=0;
sigaction(SIGUSR1,act,0);//为当前进程安装SIGUSR1信号
sigset _ t proc _ sig _ msk//当前信号掩码字
sigset _ t old _ mask//旧信号掩码字
sigemptyset(proc _ SIG _ MSK);//清除信号集
sigaddset( proc_sig_msk,SIG usr 2);//将信号SIGUSR2添加到信号掩码集中
sigprocmask(SIG_BLOCK,proc_sig_msk,old _ mask);//以增量方式修改进程的信号掩码。
sigset _ t tmp _ sig _ msk//临时信号掩码字3354用于sigsuspend函数。
sigaddset( tmp_sig_msk,SIG usr 1);
while (1) {
printf(等待.\ n’);
SIG suspend(tmp _ SIG _ MSK);//此时,当前进程无法响应SIGUSR1
printf(运行.\ n’);
}
返回0;
}
转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。