进程间不能通信,只有通过管道才能实现两个进程之间的通信。
杀死进程的命令:kill 9 pid号
信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。
内核可以发送多少种信号?64
kill -l
命令:kill -9 pid
信号通信的框架
-信号的发送(发送信号进程):kill raise alarm
-信号的接收(接收信号进程):pause(),sleep while(1)
-信号的处理(接收信号进程):signal
1.信号的发送(发送信号进程)
1、kill函数
所需头文件 | #include <signal.h> #include <sys/types.h> | |||||
函数原型int kill(pid_t pid,int sig); | ||||||
函数传入值
sig:信号 | ||||||
函数返回值 | ||||||
成功:0 | ||||||
出错:-1 | ||||||
kill命令(实现过程一样)的程序实现实例:(int kill(pid_t pid, int sig);)
要学到字符串转换为整型的函数(int atoi(const char *nptr);)
查看运行时,程序的id号(ps -axj)
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int pid;
int sig;
if(argc<3)
{
printf("please input param");
return -1;
}
sig=atoi(argv[1]);
pid=atoi(argv[2]);
printf("sig=%d,pid=%d\n",sig,pid);
kill(pid,sig);
return 0;
}
执行结果如下:
进程a要发信号给进程b必然要告诉内核,信号相关的函数:kill函数,raise函数
2、raise函数
raise:(作用)发送信号给自己==kill(getpid(),sig);
所需要的头文件 | #include <signal.h> #include <sys/types.h> |
函数原型 | int raise(int sig); |
函数传入值 | sig信号 |
函数返回值 | 成功:0 |
失败:-1 |
例程raise函数的简单使用
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main()
{
printf("raise before");
raise(9);
printf("raise aftre\n");
return 0;
}
执行结果如下:
那为什么第一条“raise before”语句没有输出呢?
答: 因为printf这条语句没有加\n,对printf是一个库函数,有库缓存
raise作用:等于_exit(),没把库缓存写到内存里面就退出了,所以没有打印
(暂停信号)SIGTSTP信号:该信号用于暂停交互进程,用户可键入SUSP字符(通常是ctrl+z)发出这个信号。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
pid=fork();
if(pid>0)
{
sleep(8);
if(waitpid(pid,NULL,0) == 0)
{
kill(pid,9);
}
wait(NULL);
while(1);
}
if(pid==0)
{
printf("raise function before\n");
raise(SIGTSTP);
printf("raise function after\n");
exit(0);
}
return 0;
}
所以raise函数就是个给自己发信号的函数
alarm函数
信号:SIGALRM:该信号当一个定时器到时的时候发出。终止
alarm也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间到时,它向进程发送SIGALRM信号。如果忽略或者不捕获此信号,则其默认动作是终止调用该alarm函数的进程。
alarm与raise函数的比较:
相同点:让内核发送信号给当前进程
不同点:
1.alarm只会发送SIGALARM信号
2.alarm会让内核定时一段时间后发送信号,raise会让内核立刻发信号
所需头文件 | #include <unistd.h> |
函数原型 | unsigned int alarm(unsigned int seconds); |
函数传入值 | seconds:指定秒数 |
函数返回值 | 成功:如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0. |
出错:-1 |
通过程序了解alarm信号通信的框架
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int i=0;
printf("alarm before\n");
alarm(9);
printf("alarm aftre\n");
while(i<20)
{
i++;
sleep(1);
printf("process things,i=%d\n",i);
}
return 0;
}
执行结果如下:
当收到alarm信号时终止进程
2.信号接收(接收信号进程)
接收信号的进程,要有什么条件:想要使接收的进程能收到信号,这个进程不能结束:sleep
pause:使进程状态变为S(睡眠态)
所需头文件 | #include <unistd.h> |
函数原型 | int pause(void); |
函数返回值 | 成功:0,出错:-1 |
信号:SIGINT
该信号在用户键入INTR字符(Ctrl+C)时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程。
终止进程
pause(暂停):终止进程的执行
例子如下:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main()
{
int i=0;
printf("pause before\n");
pause();
printf("pause aftre\n");
while(i<20)
{
i++;
sleep(1);
printf("process things,i=%d\n",i);
}
return 0;
}
执行结果如下:
3.信号的处理(接收信号进程):signal
signal函数
自己的处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的处理方式
所需要的头文件 | #include <signal.h> | ||
函数原型 | void (*signal(int signum,void (*handler)(int)))(int); | ||
函数传入值 | signum:指定处理信号 | ||
handler: | SIG_IGN:忽略该信号 | ||
SIG_DFL:采用系统默认方式处理信号 | |||
自定义的信号处理函数指针(自己的函数) | |||
函数返回值 | 成功:设置之前的信号处理方式 | ||
出错:-1 |
对signal函数的分析
void (*signal(int signum,void (*handler)(int)))(int); |
参数:A=void (*handler)(int)==一个函数指针变量,函数的形式:含有一个整型参数,返回值为空。
void (*signal(int signum,A(int);
signal:含有两个参数,第一个参数,信号值 第二个参数 函数指针
返回值:函数指针
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
void (*signal(int signum,void (*handler)(int)))(int);
内核收到alarm的信号以后会执行myfun里面的内容,执行完myfun里面的内容后,会返回main函数执行剩下的内容
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void myfun(int signum)
{
int i;
i=0;
while(i<10)
{
printf("process signal_signum=%d\n",signum);
sleep(1);
i++;
}
return; //返回到main函数,执行剩下的内容
}
int main()
{
int i=0;
signal(14,myfun);
printf("alarm before\n");
alarm(9);
printf("alarm aftre\n");
while(i<20)
{
i++;
sleep(1);
printf("process things,i=%d\n",i);
}
return 0;
}
执行结果如下:
使用SIG_IGN的方式
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void myfun(int signum)
{
int i;
i=0;
while(i<10)
{
printf("process signal_signum=%d\n",signum);
sleep(1);
i++;
}
return;
}
int main()
{
int i=0;
signal(14,myfun);
printf("alarm before\n");
alarm(9);
printf("alarm aftre\n");
signal(14,SIG_IGN);
while(i<20)
{
i++;
sleep(1);
printf("process things,i=%d\n",i);
}
return 0;
}
执行结果如下:
当使用默认处理方式时,SIG_DFL
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void myfun(int signum)
{
int i;
i=0;
while(i<10)
{
printf("process signal_signum=%d\n",signum);
sleep(1);
i++;
}
return;
}
int main()
{
int i=0;
signal(14,myfun);
printf("alarm before\n");
alarm(9);
printf("alarm aftre\n");
signal(14,SIG_IGN);
signal(14,SIG_DFL);
while(i<20)
{
i++;
sleep(1);
printf("process things,i=%d\n",i);
}
return 0;
}
执行结果如下:
例子:父子进程方式进行信号通信。
程序设计思路:调用fork函数后,程序分裂成一样两个程序,父进程中每秒打印一次,当子进程10秒以后使用kill(getppid,信号)函数发送信号给父进程通过signal函数接受到信号,执行myfunc函数中的内容执行完了以后再执行父进程中的内容,10秒后子进程有通过kill发送一个信号给父进程,父进程接受到信号以后执行myfun1函数里面的内容,当内容执行完了,回到main函数中执行父进程
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void myfunc(int signum)
{
int i=0;
while(i<5)
{
printf("receive signum=%d,i=%d\n",signum,i);
sleep(1);
i++;
}
return;
}
void myfunc1(int signum)
{
printf("receive signum=%d\n",signum);
wait(NULL);
return;
}
int main()
{
pid_t pid;
pid=fork();
if(pid>0)
{
int i=0;
signal(10,myfunc);
signal(17,myfunc1);
while(1)
{
printf("parent process things,i=%d\n",i);
sleep(1);
i++;
}
}
if(pid==0)
{
sleep(10);
kill(getppid(),10);
sleep(10);
exit(0);//kill(getppid(),SIG_CHLD)
}
return 0;
}
执行结果如下: