当前位置:   article > 正文

Linux编程基础 4.3:信号学习之信号阻塞_linux c++信号量提前阻塞

linux c++信号量提前阻塞

4 信号阻塞

在进程PCB中存在两个信号集:信号掩码(signal mask)、未决信号集(signal pending)。
两个信号集都是位图,每一位对应一个信号:

  • 若mask中某个位被设置为1,则对应的信号将被屏蔽;
  • 此时内核会修改pending中该信号对应的位为1,使该信号处于未决态;
  • 除非该信号被解除屏蔽,否则内核不会再向进程发送这个信号;
  • 用户不能直接操作未决信号集,但可以自定义的set位图与mask进行位操作,以达到屏蔽或解除屏蔽的目的。

4.1 信号集设定函数

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

函数功能:设定自定义信号集:

  • sigemptyset:将指定信号集清0;
  • sigfillset:将指定信号集置1;
  • sigaddset:将某个信号加入指定信号集;
  • sigdelset:将某个信号从信号集中删除;
  • sigismember:判断某个信号是否已加入指定信号集。

参数说明

  • set:一个sigset_t类型的指针,sigset_t是系统自定义类型,其实质是一个位图,一般用户不会对位进行直接操作的,通过上述函数进行间接操作。

返回值说明

  • 成功返回0
  • 不成功返回-1

4.2 sigprocmask函数

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • 1
  • 2

函数功能:自定义位图设定完成后,要与mask位图进行位操作,以改变mask位图中的数据。
通过自定义的信号集set,用来和PCB中的mask信号屏蔽字进行位与、位或、取反位与等操作,用来改变mask信号屏蔽字的位图状态。就可以实现阻塞、未阻塞等操作。

参数说明

  • how:用于设置位操作的方式,取值如下:
    – SIG_BLOCK:set位图中需要屏蔽的信号,即mask = mask | set;
    – SIG_UNBLOCK:set位图中需要解除屏蔽的信号,即mask = mask & ~set;
    – SIG_SETMASK:set位图用于替代mask的新屏蔽集,即mask = set。
  • set和oldset:指向位图的指针,set指向用户自定义位图,oldset记录原mask位图的值。

返回值说明

  • 成功返回0;
  • 不成功返回-1,并设置errno。

特别说明
系统中什么时候产生什么信号是有规律的,用户进程不应随便对mask进行修改。因此在用户进程中的功能实现之后,应尽量使用sigprocmask的传出参数oldset恢复mask。

4.3 sigpending函数

#include <signal.h>
int sigpending(sigset_t *set);
  • 1
  • 2

函数功能:获取当前进程中未决信号集的信息。

参数说明

  • set:一个传出参数,获取未决信号集信息。

返回值说明

  • 1:成功
  • -1:不成功

【案例 1】以2号信号为例,通过位操作函数sigprocmask和sigpending获取信号状态。

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

void printset(sigset_t *paraPed){
    int i;
    for(i = 1; i < 32; i ++){
        if(sigismember(paraPed, i) == 1){
            putchar('1');
        }else{
            putchar('0');
        }//of if
        printf("\n");
    }//of for i
}//of printset

int main(){
    sigset_t tempSet, tempOldSet, tempPed;

    sigemptyset(&tempSet);          //初始化
    sigaddset(&tempSet, SIGINT);    //将2号信号SIGINT加入tempSet
    sigprocmask(SIG_BLOCK, &tempSet, &tempOldSet); //位操作
    while(1){
        sigpending(&tempPed);
        printset(&tempPed);
        sleep(1);
    }//of while
    return 0;
}//of main

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

执行程序,终端会不断打印进程PCB中的未决信号集。初始情况下进程未决信号集中的每一位都应为0,因此打印的信息如下:

00000000000000000000000000000000
  • 1

使用kill命令或组合按键Ctrl+C驱使内核发送信号SIGINT给当前进程。进程第一次接收到信号SIGINT后,sigprocmask被触发,此后终端打印的信息如下:

01000000000000000000000000000000
  • 1

之后继续向进程发送SIGINT信号,终端打印信息不变,说明信号SIGINT被成功屏蔽。

【案例2】信号操作集测试

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include <sys/mman.h>
#include <errno.h>
#include <signal.h>//信号头文件

//该函数用于未决信号集的打印,传入未决信号的sigpending函数的传出参数
void print_set(sigset_t *paraset){
	int i = 0;
	for(;i<32;i++){
		if(sigismember(paraset,i)){//查看信号在不在创建的信号集中,在返回1,不在返回0
			printf("1");//在打印1字符
		}else{
			printf("0");//不在打印0字符
		}//of if
	}//of for 
	printf("\n");//添加换行符号
}//of print_set

void sys_error(const char* paraString){
	perror(paraString);
	exit(1);
}

int main(int argc,char* argv[]){
	sigset_t tempSet;//创建的信号集
	sigset_t tempOldset;//用于传出参数,旧的mask
	sigset_t tempPdset;//用于未决信号集的传出,只读的。

	sigemptyset(&tempSet);//清空信号集
	sigaddset(&tempSet, SIGINT);//添加各种信号
	sigaddset(&tempSet, SIGQUIT);
	sigaddset(&tempSet, SIGBUS);
	sigaddset(&tempSet, SIGKILL);

	//设置信号屏蔽字
	int tempRet = sigprocmask(SIG_BLOCK,&tempSet,&tempOldset);//将自我创建的信号集进行阻塞。
	if(tempRet == -1){
		sys_error("sigprocmask error");
	}//of if
	
    int tempRet1 = 0; //用于判断sigpending函数是否执行成功
    
	while(1){
		tempRet1 = sigpending(&tempPdset);//传出未决信号集pdset
        
        if(tempRet1 == -1){
            sys_error("sigpending error");
        }
		print_set(&tempPdset);//打印未决信号集
		sleep(1);
	}

	return 0;
}

haitu@ubuntu:/opt/linux_test/signal/signal2$ ./sigset 
10000000000000000000000000000000
10000000000000000000000000000000
10000000000000000000000000000000
10000000000000000000000000000000
^C10100000000000000000000000000000    //输入ctrl + c
10100000000000000000000000000000
10100000000000000000000000000000
10100000000000000000000000000000
    
//想要关掉的话,可以使用另一个窗口,使用 ps ajx 来查看该进程的pid
//使用命令kill -9 pid号 进行关闭该进程。(SIGKILL信号是不能够屏蔽的,也不能够忽略捕捉)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

信号操作集函数的使用原理:

#使用kill -l命令可以获取到信号的列表
haitu@ubuntu:/opt/linux_test/signal/signal2$ kill -l
 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	
#***注意:其中 9 号和 19 号信号比较特殊,只能执行默认动作,不能忽略捕捉,不能设置阻塞。***
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/460172
推荐阅读
相关标签
  

闽ICP备14008679号