linux学习-信号相关函数

未决:在信号产生和递送之间的时间间隔内,我们称信号是未决的。

阻塞信号递送:如果为进程产生了一个阻塞信号,而且对该信号的动作是默认动作或捕捉该信号,则为该进程将此信号保持为未决的,直到进程对此信号解除阻塞,或者对此信号的动作更改为忽略。

信号屏蔽字:每个进程都有一个信号屏蔽字,它规定了当前要阻塞递送到该进程的信号集。

信号集:可以表示多个信号的数据类型,定义数据类型为sigset_t

#include<signal>
int sigemptyset(sigset_t *set);               //初始化信号集为空
int sigfillset(sigset_t *set);                //初始化信号集包括所有信号
int sigaddset(sigset_t *set,int signo);       // 将信号signo加入到set信号集
int sigdelset(sigset_t *set,int signo);       //将信号signo从信号集中删除

1.函数kill和raise

#include<signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
                            返回值: 成功返回0,失败返回-1

kill的pid参数
pid>0 将该信号发送进程ID为pid的进程
pid==0 将信号发送给与发送进程同一进程组的所有进程,但不包 括系统进程集,既内核进程和init。
pid<0 将该进程发送给其他进程组ID为pid绝对值的所有进程,不包括系统进程集
pid==-1将该信号发送给进程有权限向它们发送信号的所有进程,不包括系统进程集
如上所述,进程发送信号是要权限的,超级用户可以发送给所有的进程。非超级的,发送者的实际用户ID或者有效用户ID必须等于接收者的实际用户ID或者有效用户ID。

2.函数alarm和pause
alarm函数可以设置一个闹钟时间,超时产生SIGALRM信号。如忽略或者不捕捉该信号,系统默认动作是终止调用alarm函数的进程。

#include<unistd.h>
unsigned int alarm(unsigned int seconds);
                          返回值:0,或者是以前设置的闹钟时间的剩余时间

每个进程只能有一个闹钟时间。如果在调用alarm之前已经为该进程注册的闹钟时间还未超时,则该闹钟的剩余时间作为本次alarm函数调用的值返回。以前注册的闹钟时间则被新值代替。如果本次调用的seconds值是0,则取消以前的闹钟,其剩余值,作为alarm函数的返回值。
pause函数调用进程挂起,直到捕捉到一个信号

#include<ubistd.h>
int paush(void);     
                                 返回值:-1;errno设置为EINTR

给出一个用alarm和pause实现sleep的实例

#include<stdio.h>
#include<signal.h>
#include<setjmp.h>
#include<ubistd.h>

static jmp_buf env_alrm;
static void myalrm(int signo)         //信号处理函数
{
	longjmp(env_alrm,1);              //局部跳转
	
}


int mysleep(int sec)
{
	int minsec,ret,tmp=0;
	if(signal(SIGALRM,myalrm)==SIG_EER)
		return sec;
	minsec=alrm(0);                  //得到上一次未超时定时器所剩的时间
	ret=sec>minsec?(sec-minsec):0;
	
	if(setjmp(env_alrm)==0)          //局部跳转
	{
		if(minsec)                   //考虑之前设置了定时器
			alarm(minsec<sec?minsec:sec);        //用时间短的做定时 
		else
			alarm(sec);
		    sleep(9);
		    pause();
		
	}
	tmp=alarm(0);                    //睡眠时,被其他信号打断而剩下的未睡眠时间
	if(minsec>sec){                  //若前面登记的定时器比睡眠时间长,退出后需要复位之前定时器剩下的时间
		alarm(minsec-sec);
	}
	
	if(tmp)
		ret+=tmp;
	return ret;
	
	
	
}


int main()
{
	int othersec;
	alarm(6);
	othersec=mysleep(3);
	printf("return %d\n",othersec);
	return 0;
}

3.函数sigprocmask
调用函数sigprocmask可以检测和更改当前阻塞而不能递送给进程的信号集。

#include<signal.h>
int sigprocmask(int how,const sigset_t *restrict set,sigset_t *restrict oset);
                            返回值:成功返回0,失败返回-1;

若oset为非空指针,进程当前的信号屏蔽子通过oset返回。
若set为非空指针,参数how指示进行何种操作。若为空,则不改变当前信号屏蔽字,how参数也无用。

how说明
SIG_BLOCK新set中的信号加到信号屏蔽字中
SIG_UNBLOCK将set中信号从当前信号屏蔽子中取出
SIG_SETMASK该进程新的信号屏蔽是set指向的值

4.函数sigismember
函数sigismember用来测试参数signum 代表的信号是否已加入至参数set信号集里。

int sigismember(const sigset_t *set,int signum)
返回值:有该信号,返回1,无则返回0;出错返回-1

5.函数sigpending
sigpending函数返回在送往进程的时候被阻塞挂起的信号集合。这个信号集合通过参数set返回。

#include<signal.h>
int sigpengding(sigset_t *set);
                                             返回值:成功返回0,出错返回-1

下面这个例程,用到了上面几个函数

static void sig_quit(int signo)
{
	printf("caught sigquit\n");
}

int main()
{
 sigset_t newmak,oldmask,pendmsk;
 if(signal(SIGQUIT,sig_quit)==SIG_ERR)
 		printf("can not catch quit\n");

sigemptyset(&newmask);                                 //信号集清空函数
sigaddmask(&newmask,SIGQUIT);                 //将信号添加到信号集中
if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)      //将信号SIGQUIT添加到信号屏蔽字中
        printf("err\n");
 sleep(5);
 if(sigpending(&pendmask)<0)                        //检测当前进程中阻塞的信号,通过pendmask返回
 		printf("sigpending err\n");
 if(sigismember(&pendmask,SIGQUIT))         //检测SIGQUIT是否在pendmask信号集中
 		printf("sigquit pending\n");
 
 if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)   //将SIGQUIT信号取消屏蔽
 		printf("err\n");
 sleep(5);
 exit(0);
}

6.函数sigaction
sigaction函数的功能是检查或者修改与指定信号相关联的动作。此函数取代了早期使用的signal函数。

#include<signal.h>
int sigaction(int signo,conststruct sigaction*restrict act,
struct sigaction*restrict oact);
返回值:成功返回0,失败返回-1

给信号signo设置新的信号处理函数act, 同时保留该信号原有的信号处理函数oldact。
此函数用到了一个数据结构

struct sigaction{
  void (*sa_handler)(int);
   sigset_t sa_mask;
  int sa_flag;
  void (*sa_sigaction)(int,siginfo_t*,void*);
};

sa_handler字段:包含一个信号捕捉函数的地址。

sa_mask字段:说明了一个信号集,在调用该信号捕捉函数之前,这一信号集要加进进程的信号屏蔽字中。仅当从信号捕捉函数返回时再将进程的信号屏蔽字复位为原先值。

sa_flags字段:指定对信号进行处理的 各个选项。有张表格,我就不列了,自己百度吧。简单说明下面程序用到的两个标志
SA_NODEFER: 当信号处理函数正在进行时,不堵塞对于信号处理函数自身信号功能。
SA_RESETHAND:当用户注册的信号处理函数被执行过一次后,该信号的处理函数被设为系统默认的处理函数。

sa_sigaction字段:是一个替代的信号处理程序,当sa_flags 为SA_SIGINFO时,使用该信号处理程序。sa_sigaction和sa_handler,应用只能一次调用其中一个。

static void sig_quit(int signo)
{
 printf("catch quit\n");
}


int main()  
{  
        struct sigaction act,oldact;  
        act.sa_handler  = sig_quit;  
	    act.sa_flags = SA_NODEFER | SA_RESETHAND;     
        sigaction(SIGINT,&act,&oldact);                                  
       
        sleep(5);  
        printf("hello \n");
  
        return 0;  
}

7.函数sigsuspend
sigsuspend函数和pause函数一样,可以使进程挂起(进入睡眠状态),直至有信号发生。
sigsuspend函数的参数是一个信号集,这个信号集是用来屏蔽信号的,信号集中存放了要屏蔽的信号。
如果该信号集为空的话,sigsuspend就不屏蔽任何信号,任何信号都可以使进程从挂起状态唤醒,这就与pause函数一样了。

#include<signal.h>
int sigsuspend(const sigset_t *sigmask);
                                            返回值:-1,并将errno设置为EINTR

可以用于保护代码临界区,使其不被特定的信号中断

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stddef.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/termios.h>
#include<sys/ioctl.h>
#include<pwd.h>
#include<setjmp.h>
#include<time.h>

static void sig_init(int);

int main()
{
	sigset_t newmask,oldmask,waitmask;
	printf("hello");
	
	if(signal(SIGINT,sig_init)==SIG_ERR)
		perror("signal");
	sigemptyset(&waitmask);
	sigaddset(&waitmask,SIGUSR1);
	sigemptyset(&newmask);
	sigaddset(&newmask,SIGINT);
	
	if(sigprocmask(SIG_BLOCK,&newmask,&oldmask)<0)            //将SIGINT加入到信号屏蔽字中,以oldmask返回
		perror("sigprocmask");
		
	printf("ok");
	if(sigsuspend(&waitmask)!=-1)                             //将sigusr1屏蔽
		perror("sigsuspend");
	
	if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)              //将阻塞信号SIGINT恢复
		perror("sigprocmask");
	exit(0);
	
	
}

static void sig_init(int signo)
{
	printf("how are you\n");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值