进程间通信信号linux,进程间通信--信号(进程间通信唯一的异步方式)

A. kill  -l

69fd9f6388ae6a3938d2508fa4d10403.png

B.常用信号的含义045dcaf7ac4d96b380278d29f762d163.png

20181fbb41f0e2ea93343d44d4d9f722.png

三、信号的产生

A.用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,例如ctr+c产生SIGINT,  ctr + \产生SIGQUI信号,ctr + z产生SIGTSTP。

B.硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给当前进程 。

C.一个进程调用int kill(pid_t pid,int sig)函数可以给另一个进程发送信号

D.可以用kill命令给某个进程发送信号,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。

E.当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。

四、进程对信号的处理

A.忽略此信号

B.执行该信号的默认处理动作

C.提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式成为捕捉(Catch)一个信号。

五、相关信号API

A.通过系统调用向一个指定的进程发送信号

837d7c4d97053dc540e1fdcbf6867191.png

参数说明:

第一个参数:指定发送信号的接收线程

第二个参数:信号的signum

案例一、

父进程从终端输入signum,然后发给子进程

点击(此处)折叠或打开

#include

#include

#include

#include

int main()

{

int pid;

if((pid = fork()) < 0)

{

perror("Fail to fork");

exit(EXIT_FAILURE);

}else if(pid == 0){

while(1);

}else{

int signum;

while(scanf("%d",&signum) == 1)

{

kill(pid,signum);

system("ps -aux | grep a.out");

}

}

return 0;

}

运行结果如下:d350301e1af9642200f48be9f987ffb2.png

B.捕捉一个信号a8428917a0d3900ee09b22de93bb6e72.png

对应的APId12e3dbd21a7ecd9d4f7aa0c019087e0.png

其原型:75583af0b85da048baccfbca786d62ec.png

我们一般都是用第一个,也就是通过typedef改写过的。

注意:signal函数我一般认为其是向内核注册当前进程收到信号的处理的方式。

signal(SIGINT,handler);

参数说明:

signum  :  指定信号

handler  :  SIG_IGN忽略该信号,SIG_DFL采用系统默认方式处理信号,自定义的信号处理函数指针。

案例探究:

通过异步方式,给子进程收尸

注意:子进程在终止时会给父进程发SIGCHLD,该信号的默认处理动作是忽略,父进程可以自定义SIGCHLD信号的处理函数,这样父进程只需要专心处理自己的工作,不必关心子进程了,子进程终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程即可。

点击(此处)折叠或打开

#include

#include

#include

#include

void child_exit_handler(int signum)

{

if(signum == SIGCHLD)

{

printf("Child exit.\n");

wait(NULL);

}

}

int main()

{

int pid;

int i = 0;

//想内核注册,处理 SIGCHLD信号的方式

signal(SIGCHLD,child_exit_handler);

if((pid = fork()) < 0)

{

perror("Fail to fork");

exit(EXIT_FAILURE);

}else if(pid == 0){

for(i = 0;i < 5;i ++)

{

printf("child loop.\n");

sleep(1);

}

}else{

for(i = 0;i < 5;i ++)

{

printf("Father loop.\n");

sleep(2);

}

}

exit(EXIT_SUCCESS);

}

C.闹钟函数alarmbf899fb707987ddf47f1bc39c5fbf9a3.png

larm()也称为闹钟函数,它可以在进程中设置一个定时器。当定时器指定的时间到时,内核就向进程发送SIGALARM信号。

seconds:指定的秒数,如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。

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

alarm(100);

........

......

alarm(5);

出错:-1

案例探究:

点击(此处)折叠或打开

#include

#include

#include

void handler(int signum)

{

if(signum == SIGALRM)

{

printf("Recv SIGALARM.\n");

}

exit(EXIT_SUCCESS);

}

int main()

{

int count = 0;

int n = 0;

signal(SIGALRM,handler);

n = alarm(10);

printf("n = %d.\n",n);

sleep(2);

n = alarm(5);

printf("n = %d.\n",n);

while(1)

{

printf("count = %d.\n", ++count);

sleep(1);

}

return 0;

}运行结果如下:

5143b48a3c1b946b8d37d122007091d2.png

案例二、综合案例

使用FIFO实现clientA与clientB之间聊天

A.输入quit后,两个进程退出

B.如果在20秒内,没有等到另一端发来的消息,则认为对方已不在,此时终止。

clientA:

点击(此处)折叠或打开

#include

#include

#include

#include

#include

#include

#include

#include

#define MAX 100

void signal_handler(int signum)

{

static int flag = 0;

switch(signum)

{

case SIGALRM:

if(flag == 0)

{

printf("The people is leaving,the system is closed in 10 seconds \

and you can input 'ctrl + c' cancel.\n");

alarm(10);

}else{

kill(getppid(),SIGKILL);

usleep(500);

exit(EXIT_SUCCESS);

}

flag = 1;

break;

case SIGINT:

printf("The alarm is cancel.\n");

alarm(0);

break;

}

}

int child_recv_fifo(char *fifo_name)

{

int n,fd;

char buf[MAX];

if((fd = open(fifo_name,O_RDONLY)) < 0)

{

fprintf(stderr,"fail to open %s : %s.\n",fifo_name,strerror(errno));

return -1;

}

signal(SIGALRM,signal_handler);

signal(SIGINT,signal_handler);

alarm(15);//璁剧疆瀹氭椂鍣?

while(1)

{

n = read(fd,buf,sizeof(buf));

buf[n] = '\0';

printf("Read %d bytes : %s.\n",n,buf);

if(strncmp(buf,"quit",4) == 0 || n == 0)

{

kill(getppid(),SIGKILL);

usleep(500);

exit(EXIT_SUCCESS);

}

alarm(15);

}

return 0;

}

int father_send_fifo(char *fifo_name,int pid)

{

int n,fd;

char buf[MAX];

if((fd = open(fifo_name,O_WRONLY)) < 0)

{

fprintf(stderr,"Fail to open %s : %s.\n",fifo_name,strerror(errno));

return -1;

}

signal(SIGINT,SIG_IGN);

while(1)

{

getchar();

printf(">");

fgets(buf,sizeof(buf),stdin);

buf[strlen(buf)-1] = '\0';

write(fd,buf,strlen(buf));

if(strncmp(buf,"quit",4) == 0)

{

kill(pid,SIGKILL);

usleep(500);

exit(EXIT_SUCCESS);

}

}

return 0;

}

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

{

int pid;

if(argc < 3)

{

fprintf(stderr,"usage %s argv[1].\n",argv[0]);

exit(EXIT_FAILURE);

}

if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)

{

perror("Fail to mkfifo");

exit(EXIT_FAILURE);

}

if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)

{

perror("Fail to mkfifo");

exit(EXIT_FAILURE);

}

if((pid = fork()) < 0)

{

perror("Fail to fork");

exit(EXIT_FAILURE);

}else if(pid == 0){

child_recv_fifo(argv[2]);

}else{

father_send_fifo(argv[1],pid);

}

exit(EXIT_SUCCESS);

}

client B

点击(此处)折叠或打开

#include

#include

#include

#include

#include

#include

#include

#include

#define MAX 100

void signal_handler(int signum)

{

static int flag = 0;

switch(signum)

{

case SIGALRM:

if(flag == 0)

{

printf("The people is leaving,the system is closed in 10 seconds \

and you can input 'ctrl + c' cancel.\n");

alarm(10);

}else{

kill(getppid(),SIGKILL);

usleep(500);

exit(EXIT_SUCCESS);

}

flag = 1;

break;

case SIGINT:

printf("The alarm is cancel.\n");

alarm(0);

break;

}

}

int child_recv_fifo(char *fifo_name)

{

int n,fd;

char buf[MAX];

if((fd = open(fifo_name,O_RDONLY)) < 0)

{

fprintf(stderr,"fail to open %s : %s.\n",fifo_name,strerror(errno));

return -1;

}

signal(SIGALRM,signal_handler);

signal(SIGINT,signal_handler);

alarm(15);//璁剧疆瀹氭椂鍣?

while(1)

{

n = read(fd,buf,sizeof(buf));

buf[n] = '\0';

printf("Read %d bytes : %s.\n",n,buf);

if(strncmp(buf,"quit",4) == 0 || n == 0)

{

kill(getppid(),SIGKILL);

usleep(500);

exit(EXIT_SUCCESS);

}

alarm(15);

}

return 0;

}

int father_send_fifo(char *fifo_name,int pid)

{

int n,fd;

char buf[MAX];

if((fd = open(fifo_name,O_WRONLY)) < 0)

{

fprintf(stderr,"Fail to open %s : %s.\n",fifo_name,strerror(errno));

return -1;

}

signal(SIGINT,SIG_IGN);

while(1)

{

getchar();

printf(">");

fgets(buf,sizeof(buf),stdin);

buf[strlen(buf)-1] = '\0';

write(fd,buf,strlen(buf));

if(strncmp(buf,"quit",4) == 0)

{

kill(pid,SIGKILL);

usleep(500);

exit(EXIT_SUCCESS);

}

}

return 0;

}

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

{

int pid;

if(argc < 3)

{

fprintf(stderr,"usage %s argv[1].\n",argv[0]);

exit(EXIT_FAILURE);

}

if(mkfifo(argv[1],0666) < 0 && errno != EEXIST)

{

perror("Fail to mkfifo");

exit(EXIT_FAILURE);

}

if(mkfifo(argv[2],0666) < 0 && errno != EEXIST)

{

perror("Fail to mkfifo");

exit(EXIT_FAILURE);

}

if((pid = fork()) < 0)

{

perror("Fail to fork");

exit(EXIT_FAILURE);

}else if(pid == 0){

child_recv_fifo(argv[1]);

}else{

father_send_fifo(argv[2],pid);

}

exit(EXIT_SUCCESS);

}

D.将进程挂起函数pauseff6ee353c685c6aac807df6610740a33.png

解释如下:3224e130dd0d93b1db7d18482173a84d.png

案例如下:8200d7ba37175c1c1baac7da69e69a1f.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值