《Linux 编程 c》学习笔记--信号

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32095699/article/details/88609002

Linux共有64个信号类型:


 信号分类:
1.不可靠信号(非实时)

 编号1~31的信号,不支持排队,可能造成信号丢失

2个特殊信号:

SIGSTOP(19) : 中断进程的执行,对应键盘的输出为“Ctrl +C”

SIGKILL(9) : 强制进程退出,对应键盘的输出为“Ctrl +\”

SIGSTOP和SIGKILL不允许被捕捉,忽略或者阻塞!

2.可靠信号 (实时)

编号34~63,支持排队,不会丢失


信号处理方式:

Term:终止当前进程

Ign:忽略该信号

Core:终止当前进程并且使用Core Dump保存进程用户空间的内存数据到core文件

Stop:停止当前进程

Cont:继续执行之前停止的进程


信号注册 

signal函数

sighandler_t signal(int signum,sighandler_t handler);

signum:注册的信号

handler:函数处理函数

例子:

重定义SIGINT和SIGQIUT

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

void signalDeal(int sig){
	if(sig == SIGINT){
		printf("please type Ctrl+C\n");
	}
	else if(sig ==SIGQUIT){
		printf("please type Ctrl+/\n");
	}
	else{
		printf("other signals\n");
	}

}
int main(int argc, char const *argv[])
{
	signal(SIGINT,signalDeal);
	signal(SIGQUIT,signalDeal);
	while(1){

	}
	return 0;
}

运行.c文件,分别按下Ctrl+C和Ctrl+\

./signal 
^Cplease type Ctrl+C
^\please type Ctrl+/
^Z
[2]+  已停止               ./signal
 

使用Ctrl+Z停止进程


发送信号

1.kill函数

int kill(pid_t pid,int sig)

参数: 
pid:可能选择有以下四种

1. pid>0时,将信号发送给进程号为pid的进程。
2. pid=0时,信号将送往所有与目前进程相同进程组的进程
3. pid=-1时,信号将送往所有调用进程有权给其发送信号的进程,除了进程1(init)。
4. pid<-1时,信号将送往以-pid为组标识的进程。

例子:父进程向子进程发送SIGABRT信号,终止子进程。

!注意 fork()>0时,表明此时是父进程在运行,返回的值是子进程的pid

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
	pid_t pid = fork();
	if(pid<0){
		printf("error!\n");
	}
	else if(pid==0){
		printf("this is child,id =%d \n",getpid());
		sleep(5);
		printf("child didn't receive signal...\n");
		return 1;
	}
	else{
		sleep(2);
		printf("this is parent\n");
		printf("pid = %d\n",pid );
		if(kill(pid,SIGABRT)==-1){
			printf("fail to call kill function!\n");
		}
	}

	return 0;
}

输出:

this is child,id =12414 
this is parent
pid = 12414 

2.raise函数

int raise(int sig)

当前进程向自身发送一个信号

等同于调用:

kill(getpid(),signal)

raise返回成功=0,返回失败=-1

例子:raise向自身进程发送一个SIGABRT信号

(SIGABRT为调用abort函数时产生的信号,会使进程异常终止)

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

int main(int argc, char const *argv[])
{
	printf("raise function\n");
	if(raise(SIGABRT)==-1){
		printf("fail to call raise\n");
		exit(1);
	}
	printf("fail to send signal\n");

	return 0;
}

输出:

raise function
已放弃 (核心已转储) 


进程间使用信号同步

例子:

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

void sigUSER1Deal(int sig){
	time_t timetmp;
	if(sig == SIGUSR1){
		time(&timetmp);
		printf("%s\n",ctime(&timetmp));
	}
}
int main(int argc, char const *argv[])
{
	pid_t pid = fork();
	if(pid<0){
		printf("error\n");
		return 1;
	}
	else if(pid ==0){
		signal(SIGUSR1,sigUSER1Deal);
		while(1){

		}
	}
	else{
		//send SIGUSER1 to its child
		sleep(1);//let its child signal SIGUSER1
		while(kill(pid,SIGUSR1)==-1){
			sleep(1);
		}
		printf("parent send SIGUSER1 sucessfully \n");

	}
	return 0;
}

输出:

parent send SIGUSER1 sucessfully 
Sun Mar 17 10:56:48 2019


定时信号

alarm

unsigned int alram(unsigned int seconds);

seconds秒后向进程本身发送一次SIGALARM信号(又称为闹钟时间)。

例子:

alarm(3);

定时3秒向进程本身发送SIGALRM信号

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void signalDeal(int sig){
	if(sig ==SIGALRM){
		printf("this is the alarm time function\n");
	}
}
int main(int argc, char const *argv[])
{
	
	signal(SIGALRM,signalDeal);
	alarm(3);
	for (int i = 0; i < 15; ++i)
	{
		printf("sleeping ..%d\n",i );
		sleep(1);
	}
	return 0;
}

输出:

sleeping ..0
sleeping ..1
sleeping ..2
this is the alarm time function
sleeping ..3
sleeping ..4
sleeping ..5
sleeping ..6
sleeping ..7
sleeping ..8
sleeping ..9
sleeping ..10
sleeping ..11
sleeping ..12
sleeping ..13
sleeping ..14

每隔三秒发送一次SIGALRM:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
void signalDeal(int sig){
	if(sig ==SIGALRM){
		printf("this is the alarm time function\n");
		alarm(3);

	}
}
int main(int argc, char const *argv[])
{
	
	signal(SIGALRM,signalDeal);
	alarm(3);
	for (int i = 0; i < 15; ++i)
	{
		printf("sleeping ..%d\n",i );
		sleep(1);
	}
	return 0;
}

输出:

sleeping ..0
sleeping ..1
sleeping ..2
this is the alarm time function
sleeping ..3
sleeping ..4
sleeping ..5
this is the alarm time function
sleeping ..6
sleeping ..7
sleeping ..8
this is the alarm time function
sleeping ..9
sleeping ..10
sleeping ..11
this is the alarm time function
sleeping ..12
sleeping ..13
sleeping ..14
this is the alarm time function 


信号集

参考链接:https://blog.csdn.net/linux_ever/article/details/50344837 

用来表示多个信号的数据类型被称为Linux信号集,定义格式为:

sigset_t位于signal.h中

typedef struct{

    unsigned long sig[_NSIG_WORDS];

}sigset_t;

例子:

SIGINT信号设置阻塞,查看未决关键字 
发送SIGINT信号,查看未决关键字 
发送SIGQUIT信号解除SIGINT信号阻塞,查看未决关键字 

刚开始设置SIGINT信号为阻塞信号,当按下Ctrl+c发送中断信号SIGINT(值为2,所以后来第二位被置1)之前,未决状态字的所有位都是0,因为此时没有未抵达的信号;
当发送SIGINT信号后,因为该信号是阻塞的,所以未决状态字将第二位置为了1,表示该信号在这里阻塞了;当我按下Ctrl+\发送SIGQUIT信号后,又将SIGINT信号设置为了非阻塞的;此时可以看到未决状态字的所有位都变为了0;并且也收到了刚才阻塞的SIGINT信号;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <iostream>
using namespace std;

void handler(int sig){
	if(sig ==SIGINT){
		printf("刚才收到了信号SIGQUIT, 取消了阻塞,收到中断信号..");
	}
	else if(sig ==SIGQUIT){
		//将SIGINT信号设置为非阻塞的
       
        sigset_t un_bset;
        sigemptyset(&un_bset);
        sigaddset(&un_bset, SIGINT);
        sigprocmask(SIG_UNBLOCK, &un_bset, NULL);

	}
}


void print_pending(sigset_t * pset)
{
    int i = 0;
    cout << "未决状态字(64位):";
    for (i = 1; i <= 64; ++i){
        if(sigismember(pset, i))
            cout << 1;
        else
            cout << 0;
        if(i % 8 == 0){
            cout << " ";
        }
    }
    cout << endl;
}

int main(int argc, char const *argv[])
{
	sigset_t bset;
	sigset_t pset;

	//clear bset,set SIGINT signal
	sigemptyset(&bset);
	sigaddset(&bset,SIGINT);

	signal(SIGINT,handler);
	signal(SIGQUIT,handler);

	//将SIGINT信号设置为阻塞的
	sigprocmask(SIG_BLOCK,&bset,NULL);
	while(1){
		//得到未决状态字
		sigpending(&pset);

    	//显示未决状态字
		print_pending(&pset);

		sleep(1);
	}

	return 0;
}

1)按下Ctrl+C触发SIGINT信号,由于SIGINT被初始设为阻塞,所以未决关键字变为1,

2)按下Ctrl+\触发SIGQUIT信号,执行handler函数,设置SIGINT为非阻塞,所以,未决关键字第二位置0,此时刚刚被阻塞的SIGINT发出,执行handle函数,printf(刚才收到了信号SIGQUIT, 取消了阻塞,收到中断信号..)

输出:

未决状态字(64位):00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
未决状态字(64位):00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
未决状态字(64位):00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
^C未决状态字(64位):01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
未决状态字(64位):01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
^\刚才收到了信号SIGQUIT, 取消了阻塞,收到中断信号..未决状态字(64位):00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 
未决状态字(64位):00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 

猜你喜欢

转载自blog.csdn.net/qq_32095699/article/details/88609002