Linux进程学习之:信号通信

用户空间里面的两个进程不能直接通信,必须通过内核进行通信

用户空间中一个进程不能直接给另一个进程发信号,必须通过内核给另一个进程发信号

信号是unix或linux响应某些条件而产生的一个事件,接收到该信号的进程会采取一些相应的行动

信号通信的对象在内核中已经创建

内核空间有很多信号,可以通过命令kill -l 来查看内核中一共有多少种信号,我们会发现一共有64种

 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX

数字代表每一种信号的ID号,宏代表具有的功能

发送信号时,需要指定接收信号的进程ID和信号ID

比如,当我们写一个死循环代码时,我们可以通过在另一个终端输入 kill 9 进程pid来杀死死循环的进程
同样我们可以自己写一个代码,来调用linux内核提供的kill命令。

#include <iostream>
 #include <stdlib.h>
 #include <signal.h>
 
 using namespace std;
 
 int main(int argc, char *argv[]){
     int pid, sid;
     if (argc < 3){
         cout << "arg error" << endl;
         return -1;
     }
     pid = atoi(argv[1]);
     sid = atoi(argv[2]);
     kill(pid, sid);
     return 0;
 }

运行的时候,需要输入死循环进程的pid号和信号id,信号id我输入的是9,pid可以通过运行ps -aux命令先找到自己运行的进程的名字再找到进程相对应的pid号

kill函数包含在signal.h头文件中,声明如下:

/* Send signal SIG to process number PID.  If PID is zero,
   send SIG to all processes in the current process's process group.
   If PID is < -1, send SIG to all processes in process group - PID.  */
#ifdef __USE_POSIX
extern int kill (__pid_t __pid, int __sig) __THROW;
#endif /* Use POSIX.  */

前面用的kill函数是发送信号,接下来讲raise函数发送信号,与kill函数不同点是,raise函数可以给自己发送信号:

代码如下:

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

using namespace std;

int main(){
	pid_t pid = fork();
	switch (pid) {
	case -1:
		cout << "fork failed" << endl;
		exit(-1);
	case 0:
		cout << "child raise" << endl;
		raise(SIGTSTP);
		cout << "raise after" << endl;
		break;
	default:
		cout << "parent sleep" << endl;
		sleep(5);
		if (waitpid(0, nullptr, WNOHANG) == 0)
		  kill (pid, 9);
		cout << "kill child process" << endl;
		wait(nullptr);
		cout << "endl ..." << endl;
		break;
	}
	return 0;
}

上述代码解析:

子进程给自己发送暂停信号,父进程睡眠5秒后,杀掉子进程并回收子进程的资源

接下来讲alarm函数

alarm函数给当前进程发送一个信号,类似于raise函数,只不过alarm函数是过一段时间再发送,alarm函数的只有一个作用,所以调用时不用指定信号类型,只有一个参数是时间,指定时间过后,进程将被退出

代码如下所示:

#include <iostream>
#include <unistd.h>
#include <stdlib.h>

using namespace std;

int main(){
    cout << "alarm before" << endl;
    alarm(5);
    cout << "alarm after" << endl;
    int i = 0;
    while (1) {
        cout << i++ << endl;
        sleep(1);
    }
    return 0;
}

运行上面的代码可以看出,程序在5秒后退出,可知alarm函数正确发挥作用

问题? alarm函数如何发挥作用的呢?

接下来是pause( )函数,pause函数不需要参数,调用pause函数会将进程进入睡眠状态,直到传递了终止该进程的信号为止

#include <iostream>
#include <unistd.h>
#include <stdlib.h>

using namespace std;

int main(){
    cout << "pause before" << endl;
    pause();
    cout << "pause after" << endl;
    int i = 0;
    while (1) {
        cout << i++ << endl;
        sleep(1);
    }
    return 0;
}

运行如上代码,程序在pause()函数处暂停,进程进入睡眠状态,按Ctrl + c退出程序

接下来讲signal函数,signal函数有两个参数,一个是信号类型,另一个是自定义的函数指针,表示当收到对应的信号类型时执行自定义的函数

#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

using namespace std;

void myfunc(int signum){
    for (int i = 0; i < 10; i++) {
        cout << "signum = " << signum << endl;
    }
}

int main(){
    cout << "alarm before" << endl;
    signal(14, myfunc);
    alarm(5);
    cout << "alarm after" << endl;
    int i = 0;
    while (i < 10) {
        cout << i << endl;
        sleep(1);
        i++;
    }
    return 0;
}

运行上面的代码,当主函数的while循环运行到i = 4后进程接收到alarm信号,开始运行自定义的函数,自定义函数运行就结束后,继续运行主函数的while循环

注意:alarm信号的信号id是14,所以signal函数的第一个参数要输入14

备注:子进程退出用exit(0)函数会返回一个SIGCHLD信号给父进程,父进程可以使用signal函数结合自定义函数对子进程的资源进行回收,防止僵尸进程的出现。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值