linux信号处理handler2,linux学习之信号篇(二)

信号(二)

1.信号捕捉设定

#include

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);structsigaction 定义:structsigaction

{void (*sa_handler)(int);//函数指针

void (*sa_sigaction)(int, siginfo_t *, void *);//和上边的函数时互斥的,两个只能选一个

sigset_t sa_mask;//调用捕捉函数时,临时使用的阻塞函数集,避免重复嵌套,调用完成后,又恢复为之前的

int sa_flags;//指定调用上边哪个函数

void (*sa_restorer)(void);//保留,已经过时了

};

sa_handler : 早期的捕捉函数

当执行捕捉函数时,默认执行的是,当前信号的屏蔽字自动置1,当执行完后,会自动恢复,响应之前在捕捉函数执行时,发生的信号。信号产生后并不一定是第一时间被响应。

fda186d07ed17604c10984b4cd57aab2.png

信号捕捉

练习:

#include#include

void do_sig(intnum)

{

printf("I am do_sig");

printf("num=%d",num);

}int main(void)

{structsigaction act;

act.sa_handler=do_sig;//act.sa_handler=SIG_DFL;//act.sa_handler=SIG_IGN;

sigemptyset(&act.sa_mask);

act.sa_flags=0;

sigaction(SIGINT,&act,NULL);while(1)

{

printf("************")

sleep(1);

}return 0;

}

运行结果:************

************

************

^c I am do_sig

num=2//信号的编号

2.利用SIGUSR1和SIGUSR2实现父子进程同步输出

注意:子进程继承了父进程的信号屏蔽字和信号处理动作

例子:设计一个父子进程,交替数数,并打印身份。

b44d808084a979b3bc0cf400b0a1a722.png

3.C标准库信号处理函数(在window和linux,unix中都可以用)

typedef void (*sighandler_t)(int)

sighandler_t signal(intsignum, sighandler_t handler)int system(const char *command)

集合fork,exec,wait一体,子进程执行通过exec执行command

signal接口简单,可跨平台,缺点没有sigaction功能强大。

4.可重入函数(和同步异步有关,多线程有关)

b71df88f4331493603ec5a5516609c44.png

不可重入函数

*不含全局变量和静态变量是可重入函数的一个要素

* 可重入函数见man 7 signal

* 在信号捕捉函数里应使用可重入函数

* 在信号捕捉函数里禁止调用不可重入函数

例如:上述的链表的插入函数就是一个不可重入函数。

strtok就是一个不可重入函数,因为strtok内部维护了一个内部静态指针,保存上一次切割到的位置,如果信号的捕捉函数中也去调用strtok函数,则会造成切割字符串混乱,应用strtok_r版本,r表示可重入。

#include#include

int main(void)

{char buf[]="hello world itcast xwp";char *save=buf,*p;while((p=strtok_r(save," ",&save))!=NULL);

printf("%s",p);return 0;

}

输出:

hello

world

itcast

xwp

5.信号引起的竞态和异步I/O

时序竞态

int pause(void)

使调用进程挂起,直到有信号递达,如果递达信号是忽略,则继续挂起int sigsuspend(const sigset_t *mask)1.以通过指定mask来临时解除对某个信号的屏蔽,2.然后挂起等待,3.当被信号唤醒sigsuspend返回时,进程的信号屏蔽字恢复为原来的值

#include #include#include

void sig_alrm(intsigno)

{/*nothing to do*/}

unsignedint mysleep(unsigned intnsecs)

{structsigaction newact, oldact;

unsignedintunslept;

newact.sa_handler=sig_alrm;

sigemptyset(&newact.sa_mask);

newact.sa_flags= 0;

sigaction(SIGALRM,&newact, &oldact);

alarm(nsecs);

pause();//若在某一个时刻,有一个进程使用了内核,内核使用的时间是alarm(nsecs)时间,会导致pause永远不会被执行,也称之为时序竞态。

unslept = alarm(0);

sigaction(SIGALRM,&oldact, NULL);returnunslept;

}int main(void)

{while(1)

{

mysleep(2);

printf("Two seconds passed");

}return 0;

}

mysleep的改进版

unsigned int mysleep(unsigned int nsecs)//返回值时未睡够的时间,正常返回0

{struct sigaction newact, oldact;//新的动作,旧的动作

sigset_t newmask, oldmask, suspmask;//新的信号集和旧信号集,保留旧的以便恢复

unsigned intunslept;/*set our handler, save previous information*/newact.sa_handler= sig_alrm;//设置捕捉函数,必须设置

sigemptyset(&newact.sa_mask);//清零

newact.sa_flags = 0;

sigaction(SIGALRM,&newact, &oldact);/*block SIGALRM and save current signal mask*/ //阻塞SIGALRM

sigemptyset(&newmask);

sigaddset(&newmask, SIGALRM);

sigprocmask(SIG_BLOCK,&newmask, &oldmask);

alarm(nsecs);//定时//解除阻塞,恢复

suspmask =oldmask;

sigdelset(&suspmask, SIGALRM); /*make sure SIGALRM isn't blocked*/sigsuspend(&suspmask); /*wait for any signal to be caught挂起等待,当定时器到时,产生SIGALRM信号,唤起*/

/*some signal has been caught, SIGALRM is now blocked*/unslept= alarm(0);//返回未睡够的时间

sigaction(SIGALRM, &oldact, NULL); /*reset previous action*/

/*reset signal mask, which unblocks SIGALRM*/sigprocmask(SIG_SETMASK,&oldmask, NULL);return(unslept);

}

避免异步I/O的类型

sig_atomic_t

平台下的原子类型,32位是一个int型,64位是一个long型volatile防止编译器开启优化选项时,优化对内存的读写,改进异步I/O的信号传递不便的情况

6.SIGCHLD信号处理

SIGCHLD的产生条件(向父进程发送,若子进程死的话父进程负责回收子进程资源)

子进程终止时

子进程接收到SIGSTOP信号停止时

子进程处在停止态,接受到SIGCONT后唤醒时

status处理方式

pid_t waitpid(pid_t pid, int *status, intoptions)

options

WNOHANG

没有子进程结束,立即返回

WUNTRACED

如果子进程由于被停止产生的SIGCHLD, waitpid则立即返回

WCONTINUED

如果子进程由于被SIGCONT唤醒而产生的SIGCHLD, waitpid则立即返回

获取status

WIFEXITED(status)

子进程正常exit终止,返回真

WEXITSTATUS(status)返回子进程正常退出值

WIFSIGNALED(status)

子进程被信号终止,返回真

WTERMSIG(status)返回终止子进程的信号值

WIFSTOPPED(status)

子进程被停止,返回真

WSTOPSIG(status)返回停止子进程的信号值

WIFCONTINUED(status)

子进程由停止态转为就绪态,返回真

#include #include#include#include#include#include#include

void sys_err(char *str)

{

perror(str);

exit(1);

}void do_sig_child(intsigno)

{intstatus;

pid_t pid;//回收了子进程的资源

while ((pid = waitpid(0, &status, WNOHANG)) > 0)

{if(WIFEXITED(status))

printf("child %d exit %d", pid, WEXITSTATUS(status));//打印进程的退出值时多少

else if (WIFSIGNALED(status))//判断是否是被信号终止的

printf("child %d cancel signal %d", pid, WTERMSIG(status));

}

}int main(void)

{

pid_t pid;inti;//阻塞SIGCHLD

for (i = 0; i < 10; i++)

{if ((pid = fork()) == 0)break;else if (pid < 0)

sys_err("fork");

}if (pid == 0)

{int n = 18;while (n--)

{

printf("child ID %d", getpid());

sleep(1);

}returni;

}else if (pid > 0)

{//先设置捕捉//再解除对SIGCHLD的阻塞

structsigaction act;

act.sa_handler=do_sig_child;

sigemptyset(&act.sa_mask);

act.sa_flags= 0;

sigaction(SIGCHLD,&act, NULL);while (1)

{

printf("Parent ID %d", getpid());

sleep(1);

}

}return 0;

}

7.向信号捕捉函数传参

sigqueue

int sigqueue(pid_t pid, int sig, constunion sigval value)

union sigval {intsival_int;void *sival_ptr;

};

sigaction

void (*sa_sigaction)(int, siginfo_t *, void *)

siginfo_t {int si_int; /*POSIX.1b signal*/

void *si_ptr; /*POSIX.1b signal*/sigval_t si_value;/*Signal value*/...

}

sa_flags= SA_SIGINFO

8.信号中断系统调用

read阻塞时,信号中断系统调用(要习惯返回read和write的值):

1.返回部分读到的数据

2.read调用失败,errno设成EINTER

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值