进程间通信方式-信号

1.信号

1.1概念

(1)信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式。

(2)信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。

(3)3)如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

信号的声明周期:

1.2信号的相应方式

1)忽略信号:对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。

2)捕捉信号:定义信号处理函数,当信号发生时,执行相应的处理函数。

3)执行缺省操作:Linux对每种信号都规定了默认操作

1.3信号种类

SIGINT(2):中断信号,Ctrl-C 产生,用于中断进程

SIGQUIT(3):退出信号, Ctrl-\ 产生,用于退出进程并生成核心转储文件

SIGKILL(9): 终止信号,用于强制终止进程。此信号不能被捕获或忽略。

SIGALRM(14):闹钟信号,当由 alarm() 函数设置的定时器超时时产生。

SIGTERM(15):终止信号,用于请求终止进程。此信号可以被捕获或忽略。termination

SIGCHLD(17):子进程状态改变信号,当子进程停止或终止时产生。

SIGCONT(18):继续执行信号,用于恢复先前停止的进程。

SIGSTOP(19):停止执行信号,用于强制停止进程。此信号不能被捕获或忽略。

SIGTSTP(20):键盘停止信号,通常由用户按下 Ctrl-Z 产生,用于请求停止进程

2函数接口

2.1信号的发送与挂起

#include <signal.h>

int kill(pid_t pid, int sig);

功能:给指定进程发送信号

参数:pid:指定进程

        sig:要发送的信号

返回值:成功:0

        失败:-1

int raise( int sig);

功能:向当前进程发送信号

参数:sig:信号

返回值: 成功:0

        失败:-1

相当于:kill(getpid(),sig);

int pause(void);

功能:用于将调用进程挂起,直到收到被捕获处理的信号为止。

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    kill(getpid(), SIGKILL); // 给当前进程发送一个SIGKILL信号
    // raise(SIGKILL);          // 给当前进程发送一个SIGKILL信号

    pause(); // 将进程挂起,作用和死循环类似,但是不占用CPU
    while (1)
        ;

    return 0;
}

 2.2定时器

unsigned int alarm( unsigned int seconds)

功能:功能:在进程中设置一个定时器。 当定时器指定的时间到了时,它就向进程发送SIGALARM信号。系统对SIGALARM信号默认处理方式是退出进程。

参数:参数: seconds: 定时时间,单位为秒

返回值:返回值:如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。

注意:注意:一个进程只能有一个闹钟时间。如果在调用alarm时已设置过闹钟时间,则之前的闹钟时间被新值所代替。

常用操作:取消定时器alarm(0),返回旧闹钟余下秒数。

注意:

系统默认对SIGALRM(闹钟到点后内核发送的信号)信号的响应: 如果不对SIGALRM信号进行捕捉或采取措施,默认情况下,闹钟响铃时刻会退出进程。

#include <unistd.h>
#include <stdio.h>
#include<signal.h>

int main(int argc, char const *argv[])
{

    printf("%d \n", alarm(10)); // 设置闹钟十秒,到点会向当前进程发送SIGKILL信号,第一次调用,返回值为0;
    sleep(2);                   // 睡眠两秒,此时闹钟还剩八秒
    printf("%d \n", alarm(2));  // 设置闹钟两秒,到点会向当前进程发送SIGKILL信号,第二次调用,返回值为上次闹钟的剩余秒数;
    // 以最后一次闹钟为准

    pause(); // 闹钟响后进程直接退出,所以挂起肯定也结束了

    return 0;
}

2.3信号处理函数 signal()

typedef void( *sighandler_t)(int);

sighandler_t signal( int signum, sighandler_t handler);

功能:信号处理函数

参数:signum:要处理的信号

        handler:信号处理方式

                SIG_IGN:忽略信号 (忽略 ignore)

                SIG_DFL:执行默认操作 (默认 default)

                handler:捕捉信号 (handler为函数名,可以自定义)

void handler( int sig){} //函数名可以自定义, 参数为要处理的信号

返回值:成功:设置之前的信号处理方式

失败:-1

3.练习

用信号的知识实现司机和售票员问题。

1)售票员捕捉SIGINT(代表开车)信号,向司机发送SIGUSR1信号,司机打印(let's gogogo)

2)售票员捕捉SIGQUIT(代表停车)信号,向司机发送SIGUSR2信号,司机打印(stop the bus)

3)司机捕捉SIGTSTP(代表到达终点站)信号,向售票员发送SIGUSR1信号,售票员打印(please get off the bus)

4)司机等待售票员下车,之后司机再下车。

分析司机(父进程)售票员(子进程)

售票员捕捉SIGINTSIGQUITSIGUSR1

忽略: SIGTSTP

司机 捕捉SIGUSR1SIGUSR2SIGTSTP

忽略: SIGINTSIGQUIT

#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/*
售票员捕捉SIGINT(开车)、SIGQUIT(停车)信号并向司机发送信号,捕捉司机发送的下车信号
司机捕捉售票员发出的开车和停车信号,SIGTSTP(到站信号).向售票员发送下车的信号
*/

pid_t pid;

void saler(int sig)
{
    // 捕捉开车信号,并向司机发送gogogo信号
    if (sig == SIGINT)
    {
        kill(getppid(), SIGUSR1);
    }
    // 捕捉停车信号,并向司机发送stop信号
    if (sig == SIGQUIT)
    {
        kill(getppid(), SIGUSR2);
    }
    // 捕捉司机发送的下车信号
    if (sig == SIGUSR1)
    {
        printf("saler:please get off the bus \n");
        exit(0);
    }
}
void dirver(int sig)
{
    // 捕捉售票员发出的开车信号
    if (sig == SIGUSR1)
    {
        printf("dirver:let's gogogo\n ");
    }
    // 捕捉售票员发出的停车信号
    if (sig == SIGUSR2)
    {
        printf("dirver:stop the bus \n ");
    }
    // 捕捉到站信号并向售票员发出下车信号
    if (sig == SIGTSTP)
    {
        kill(pid, SIGUSR1);
        // 等待售票员下车
        wait(NULL);
        exit(0);
    }
}

int main(int argc, char const *argv[])
{
    pid = fork();
    if (pid < 0)
    {
        perror("fork error");
        return -1;
    }
    else if (pid == 0) // 子进程  售票员
    {
        printf("i am saler!\n");
        signal(SIGINT, saler);
        signal(SIGQUIT, saler);
        signal(SIGUSR1, saler);
        signal(SIGTSTP, SIG_IGN);
    }
    else // 父进程  司机
    {
        printf("i am driver\n");
        signal(SIGTSTP, dirver);
        signal(SIGUSR1, dirver);
        signal(SIGUSR2, dirver);
        signal(SIGINT, SIG_IGN);
        signal(SIGQUIT, SIG_IGN);
    }

    while (1)
    {
        pause();
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值