APUE笔记:alarm和pause竞争
来源:互联网 发布:叶子楣 知乎 编辑:程序博客网 时间:2024/06/15 13:46
笔记批注:APUE 10.10节 函数alarm和pause。
在书P269 有这样一段话:(3) 在第一次调用alarm和pause之间有一个竞争条件。在一个繁忙的系统,有可能在我们调用pause之前超时,并调用了信号处理程序,如果发生了这种情况,则在调用pause后,如果没有捕捉到其他信号,调用者将被永远挂起。 而解决的办法是用longjmp和setjmp。我看了代码后,就想着可不可以使用变量来控制,具体如下:
#include <stdio.h>#include <signal.h>static int gflag = 0 ;//当出现在pause之前执行alarm,避免一直pause情况void sigact( int signo );unsigned int sleep_self( unsigned int sec );void sig_int( int signo );//tune these loops to run for more than 5 secondsint main(int argc , char *argv[]){unsigned int ret;ret = sleep_self( 0 );printf( "return value = %u \n " , ret );return 0;}void sigact( int signo ){//do nothingprintf( "sigact\n" );gflag = 1;}unsigned int sleep_self( unsigned int sec ){int ret ,ret1;if( signal( SIGALRM , sigact ) == SIG_ERR )oops( "signal" );if( gflag == 0 ){//还没有执行alarmret = alarm( sec );printf( "test:测试从信号处理函数返回位置,若打印两次,则是从""上一栈的接下一句返回,\n" );ret1 = pause();//pause until alarmprintf( "pause return value = %d , alarm return ""value = %d \n" , ret1 ,ret);}return alarm(0);}void sig_int( int signo ){int i , j ;volatile k ; printf( "\nsig_int start \n " );k = 0;for( i = 0 ; i < 300000; i++ )for( j = 0 ; j < 8000 ; j++ )k += i*j;printf( "sig_int finished\n" );}
首先做的测试是睡眠0s ,这样做是为了确保在pause之前 调用alarm,其实我错了, 看看结果
从结果来看, 压根没有进入sigact函数,也就是执行了alarm后接着执行了pause函数,然后进入等待状态,被挂起。然后我查询了一下alarm(0),得到的解释是:当在调用alarm()前已经设置了一个闹钟,那么我们可以调用alarm(0)来取消此闹钟,并返回剩余时间。所以用alarm(0)并不能行。换招:
2.在sleep_self函数中添加代码sig_int(0);,同时修改代码ret = sleep_self( 2 );
sig_int(0);printf( "test:测试从信号处理函数返回位置,若打印两次,则是从""上一栈的接下一句返回,\n" );
printf( "after gflag = %d \n " , gflag );
也就是让alarm后 程序在进入pause前至少运行5s,我们看结果:
程序先进入sig_int , 打印sig_int start 然后过2s 打印sigact , 然后过5s打印sig_int finished ,然后就处于等待状态了,此时,gfla = 1,但还是执行了pause,说明并没有从上次运行处继续运行, 而是接着运行。
3.实验longjmp 和setjmp
#include <stdio.h>#include <signal.h>#include <setjmp.h>jmp_buf env ;//当出现在pause之前执行alarm,避免一直pause情况void sigact( int signo );unsigned int sleep_self( unsigned int sec );void sig_int( int signo );//tune these loops to run for more than 5 secondsint main(int argc , char *argv[]){unsigned int ret;//if( signal( SIGINT , sig_int ) == SIG_ERR )//oops( "signal" );ret = sleep_self( 2 );printf( "return value = %u \n " , ret );return 0;}void sigact( int signo ){//do nothingprintf( "sigact\n" );longjmp( env , 1 );}unsigned int sleep_self( unsigned int sec ){int ret ,ret1;if( signal( SIGALRM , sigact ) == SIG_ERR )oops( "signal" );if( setjmp( env ) == 0 ){//还没有执行alarmret = alarm( sec );sig_int(0);printf( "test:测试从信号处理函数返回位置,若打印两次,则是从""上一栈的接下一句返回,\n" );ret1 = pause();//pause until alarmprintf( "pause return value = %d , alarm return ""value = %d \n" , ret1 ,ret);}return alarm(0);}void sig_int( int signo ){int i , j ;volatile k ; printf( "sig_int start \n " );k = 0;for( i = 0 ; i < 300000; i++ )for( j = 0 ; j < 6000 ; j++ )k += i*j;printf( "sig_int finished\n" );}
运行结果:
可以看到执行顺序就对了,进入sig_int , 然后过两秒进入sig_act , 然后跳到setjmp比较, 不满足, 执行return alarm(0); 结束。
4.关于pause函数,APUE同页有这样一句话:只有执行了一个信号处理程序并从其返回,pause才返回。在这种情况下,pause返回-1,errno设置为EINTR。
#include <stdio.h>#include <signal.h>static int gflag = 0 ;//当出现在pause之前执行alarm,避免一直pause情况void sigact( int signo );unsigned int sleep_self( unsigned int sec );void sig_int( int signo );//tune these loops to run for more than 5 secondsint main(int argc , char *argv[]){unsigned int ret;if( signal( SIGINT , sig_int ) == SIG_ERR )oops( "signal" );ret = sleep_self( 0 );printf( "return value = %u \n " , ret );return 0;}void sigact( int signo ){//do nothingprintf( "sigact\n" );gflag = 1;}unsigned int sleep_self( unsigned int sec ){int ret ,ret1;if( signal( SIGALRM , sigact ) == SIG_ERR )oops( "signal" );if( gflag == 0 ){//还没有执行alarmret = alarm( sec );//sig_int(0);printf( "test:测试从信号处理函数返回位置,若打印两次,则是从""上一栈的接下一句返回,\n" );//printf( "after gflag = %d \n " , gflag );ret1 = pause();//pause until alarmprintf( "pause return value = %d , alarm return ""value = %d \n" , ret1 ,ret);}return alarm(0);}void sig_int( int signo ){int i , j ;volatile k ; printf( "\nsig_int start \n " );k = 0;for( i = 0 ; i < 300000; i++ )for( j = 0 ; j < 8000 ; j++ )k += i*j;printf( "sig_int finished\n" );}
运行上述代码,键入中断制符(ctrl+c)
可见, 当执行pause后,程序挂起, 键入ctrl+c后, sig_int结束后, pause也返回了-1, 程序也能够正常退出了,可见,pause函数捕捉了SIGINT信号
- APUE笔记:alarm和pause竞争
- apue-alarm和pause函数,关于信号
- alarm和pause函数
- alarm()和pause()
- alarm和pause函数
- alarm和pause函数
- APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause
- linux 信号 alarm和pause
- APUE——信号发送函数kill,raise,pause,alarm
- Linux Signal (4): alarm和pause
- Linux Signal (4): alarm和pause
- Linux Signal (4): alarm和pause
- 捉拿信号的alarm和pause函数
- Linux Signal (4): alarm和pause
- 利用函数alarm和pause模拟sleep
- APUE笔记——alarm函数
- (笔记)alarm、pause、sleep函数的使用
- alarm pause 的用法
- BestCoder Round #66 GTW likes math
- BootStrap应用实例学习笔记
- iOS应用架构谈 view层的组织和调用方案
- Android利用Gson库解析复杂结构的JSON数据
- 设计模式6大设计原则
- APUE笔记:alarm和pause竞争
- Leetcode - Reverse Vowels of a String
- kuangbin带你飞之简单搜索 B,C
- 正确重置MySQL密码
- Linux下快速安装和配置jdk8
- solr入门之使用jetty加载solrcloud
- OpenCV检测图像SURF特征
- Java获取网页内容
- getSectionForPosition()与getPositionForSection()