linux c语言 电池信息,Linux C语言 信号及信号的操作

一.信号

1.信号的作用

1.1.控制进程

1.2.实现简单的多任务

1.3.进程间交换数据

2.什么是信号

2.1.信号是一个整数

kill -l

2.2.信号是软中断(模拟中断)

中断就是在进行某个过程,随时停下来,并进行其他过程,当其他过程结束后回到原来过程的现象。

2.3.信号的工作原理

信号源(操作系统,硬件,用户程序)发出信号

系统接收到信号(信号),系统查找信号的注册表,并找到该进程(信号目的地)对应的信号处理函数(中断函数),停止原进程的实现,执行信号处理函数,执行完毕,继续原进程的执行。

信号与信号处理函数注册必须缺省哪个进程。

a.信号源(系统进程,用户进程)

b.信号目的地(进程)

c.信号(有特殊含义的整数)

d.信号处理函数(函数void(*)(int))

2.4.信号分类

不可靠信号1-31(非实时信号)

可靠信号34-64(实时信号)

2.5.信号的编程模型:

发送信号:kill函数;或者其他键盘操作。

信号处理函数:void(*)(int);

注册信号:signal函数

案例:

体会信号SIGINT=2。

处理信号2

结论:

1.信号如果用户不处理,系统会缺省处理

系统的缺省处理大部分情况,是输出信号含义,并终止进程。

信号有缺省处理,也有忽略处理

SIG_IGN  特殊的信号处理函数-忽略信号1

(void(*)(int))1

SIG_DFL  特殊的信号处理函数-缺省处理0

(void(*)(int))0

2.sleep,pause函数被信号中断后,不会再继续,而是返回.

函数类型:

可重入函数:

中断后可继续执行的函数

不可重入函数:

中断后函数不继续执行,而是返回结束。

信号中断会导致什么安全问题?

多线程本身就是数据不安全的。

2.6.发送信号

int   kill(pid_t pid,//信号的目的地进程

int sig);//信号

参数1:

>0:进程ID

=0:同一个进程组的所有进程

-1:所有进程

案例:

使用kill发送信号

结论:

1.在独立两个进程之间,使用信号通信需要知道另外一个进程ID。

2.1-31之间的信号是不可靠。

34-64信号是可靠的。

2.7.案例:使用信号控制进程。

使用信号修改摇奖程序。

2.8.案例:使用信号实现简单的多任务。

2.8.1.简易版本的信号发送函数

int raise(int sec)  向本进程发送信号

=int kill(getpid(),int sec);

2.8.2.准备工作:定时器信号

alarm    延时定时器

向系统注册,在指定的时间秒后发送一次SIGALRM信号。

setitimer  间隔定时器

向系统注册,在指定的时间微秒后每隔一个间隔时间向进程发送信号SIGALRM。

int setitimer(int which,//定时器计时方法

const struct itimerval *val,//延时与间隔时间

struct itimerval *oldval);//返回上次设置值

struct   itimerval

{

struct  timeval it_interval;//间隔时间

struct timeval  it_value;//延时时间

}

struct timeval

{

long tv_sec;//秒

long tv_usec;//微秒

}

定时器计时方法:

ITIMER_REAL    真实时间

SIGALRM

ITIMER_VIRTUAL  进程实际运行时间

SIGVTALRM

ITIMER_PROF    进程时间+内核时间

SIGPROF

案例1:使用alarm设置系统的信号发送参数案例2:使用setitimer设置间隔定时时间

结论:想马上发送信号,不要把it_value设置为0秒0微秒,而是设置为0秒1微秒。

2.8.3.使用定时器实现与时间有关的子任务

案例:

显示7位随机数与时间。

方法:

一个进程+定时器信号。

2.9.信号的操作

2.9.1.信号屏蔽

使用signal把某个信号忽略。只能对单个的信号处理,处理多个信号,需要反复调用signal函数

a.背景:

信号屏蔽的意义。

保护一段代码不受信号的中断影响。

等代码执行结束再处理信号。[信号不丢失,但被系统延迟处理]

b.信号屏蔽函数

int sigprocmask(int how,//信号操作方式

const sigset_t *sigs,//操作的信号集合

sigset_t *oldsigs);//返回原来的信号集合

信号的操作方式:

SIG_BLOCK  屏蔽信号

SIG_UNBLOCK 解除信号屏蔽

SIG_SETMASK 修改屏蔽信号

sigset_t数据集合的操作:

清空信号集合sigemptyset

添加信号到集合sigaddset

删除集合中的某个信号sigdelset

判定某个信号是否在集合中sigismember

把所有信号添加到信号集合sigfillset

编程模型:

定义信号集合sigset_t sigs;

初始化信号集合empty add del fill

设置屏蔽信号sigprocmask  SIG_BLOCK

解除屏蔽信号sigprocmask SIG_UNBLOCK

判定某个信号是否在集合中ismember

SIGSTOP   SIGKILL

2.9.2.查询被屏蔽的信号是否发生

背景:

在被屏蔽代码中,怎么知道被屏蔽的信号已经发生?

函数:

int sigpending(sigset_t *sigs);//返回发生的信号,而且该信号被屏蔽。

问题:

信号屏蔽的时候,信号发送,信号不被处理,解除信号屏蔽,信号才被处理。

在信号屏蔽中,能否处理信号?

答案:能

问题:怎么处理?

答案:解除屏蔽,然后再屏蔽。

问题:

信号屏蔽与解除屏蔽瞬间,其他信号是否会发生,导致程序解除。

信号处理函数在执行中,是否会被信号影响?肯定影响(本身信号不影响,被其他信号影响。)

2.9.3.防止信号处理函数执行中被信号影响。

a.sigsuspend函数设置屏蔽信号

该函数的作用:等待信号发生,当信号发生,并且设置新的屏蔽信号,执行信号处理函数,执行完毕,解除信号屏蔽,恢复原来的信号屏蔽,函数返回。

int sigsuspend(const sigset_t*);

等待信号:任意信号。

在等待过程中,不受参数设置的信号集合中的信号影响。

当信号发生,处理信号,同样不受参数设置的信号影响。

信号处理结束,sigsuspend恢复原来的信号屏蔽,并且sigsuspend返回。

sigsuspend该函数等待信号,没有信号发生,该函数阻塞。信号发生,则处理后返回。

结论:

1.sigsuspend 解除原来的所有信号屏蔽

2.没有信号发生,sigsuspend阻塞。

3.sigsuspend返回前,会恢复解除屏蔽的信号

4.在解除原来的信号屏蔽,设置新的信号屏蔽。

5.函数结束前,解除新的信号屏蔽

int sigsuspend(sigset_t *sig)

{

1.sigprocmask(SIG_UNBLOCK,*s,0);

2.sigprocmask(SIG_BLOCK,*sig,0);

3.等待信号发生pause

4.处理信号

5.sigprocmask(SIG_UNBLOCK,*sig,0);

6.sigprocmask(SIG_BLOCK,*s,0);

7.return 0;

}

sigsuspend未必一定要在sigprocmask环境下工作

案例:

利用sigsuspend控制进程.

作业:

1.实现摇奖。

要求:时间显示使用SIALRM信号。

控制:使用sigsuspend控制随机数进程。

注意:

使用信号控制进程.强烈建议:

sigsuspend + signal + kill

不推荐

while(1);+signal+kill

pause/sleep+signal+kill

sigsuspend有两个作用:

定点信号处理。(屏蔽信号切换具备原子性)

控制进程。

b.高级信号发送与处理函数处理信号。

#include

#include

#include

void handle(int s){

printf("信号发生.....\n");

}

main()

{

signal(45,handle);

/*printf("%d:%d\n",SIG_IGN,SIG_DFL);*/

/*signal(SIGINT,SIG_IGN);*/

while(1){

/*printf("Hello信号!\n");*/

/*sleep(1);*/

}

}

#include

#include

#include

main()

{

int i;

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

kill(4095,45);

}

}

#include

#include

#include

#include

#include

#include int isstop=0;

void handle(){

isstop=isstop==1?0:1;

}

main()

{

/*变量区*/

int i;

sigset_t si;

WINDOW *wtime,*wcode;

pid_t pid_time,pid_code;

pid_t pid_sub;

initscr();

sigfillset(&si);

sigdelset(&si,34);

noecho();

curs_set(0);

wtime=derwin(stdscr,3,10,0,COLS-10);

wcode=derwin(stdscr,3,9,(LINES-3)/2,(COLS-9)/2);

keypad(stdscr,TRUE);

keypad(wtime,TRUE);

keypad(wcode,TRUE);

box(wtime,0,0);

box(wcode,0,0);

refresh();

wrefresh(wtime);

wrefresh(wcode);

for(i=0;i<2;i++){

if(pid_sub=fork())

{

if(i==0){

pid_time=pid_sub;

}

if(i==1){

pid_code=pid_sub;

}

continue;

}

else

{

if(i==0){

/*子进程1:时间显示*/

time_t tt;

struct tm *t;

while(1){

tt=time(0);

t=localtime(&tt);

mvwprintw(wtime,1,1,"%02d:%02d:%02d",

t->tm_hour,t->tm_min,t->tm_sec);

refresh();

wrefresh(wcode);

wrefresh(wtime);

sleep(1);

}

exit(0);

}

if(i==1){

/*子进程2:随机数显示*/

int num;

signal(34,handle);

while(1){

if(isstop){

sigsuspend(&si);

}

num=rand()%10000000;

mvwprintw(wcode,1,1,"%07u",num);

refresh();

wrefresh(wtime);

wrefresh(wcode);

usleep(10000);

}

exit(0);

}

}

}

/*主进程:键盘输入*/

int ch;

while(1){

ch=getch();

if(ch=='\n'){

/*停止随机数进程*/

/*发送信号:可靠信号>=34*/

kill(pid_code,34);

}

/*退出整个任务*/

if(ch=='x' || ch=='X'){

/*通知子进程结束*/

sched_yield();

break;

}

}

wait(0);

wait(0);

delwin(wtime);

delwin(wcode);

endwin();

exit(0);

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值