学习笔记06-学习《精通UNIX下C语言编程及项目实践》

 


全局跳转

   UNIX 下的 C 语言中 , 有一对特殊的调用 : 跳转函数 原型如下 :

#include <setjmp.h>

int setjmp(jmp_buf env);

void longjump(jmp_buf env, int val);

   函数 setjmp 存储当前的堆栈环境 ( 包括程序的当前执行位置 ) 到参数 env , 当函数正常调用成功时返回 0.  函数 longjmp 恢复保存在 env 中堆栈信息 并使程序转移到 env 中保存的位置处重新执行 这两个函数联合使用 可以实现程序的重复执行 .

   函数 longjmp 调用成功后 程序转移到函数 setjmp 处执行 函数 setjmp 返回 val.  如果参数 val 的取值为 0,  为了与上次正常调用 setjmp 相区别 , 函数 setjmp 将自动返回 1.

   下面是一个使用了跳转语句的例子 它跳转两次后退出 .

[bill@billstone Unix_study]$ cat jmp1.c

#include <setjmp.h>

 

int j = 0;

jmp_buf env;

 

int main()

{

         auto int i, k = 0;

 

         i = setjmp(env);

         printf("setjmp = [%d], j = [%d], k = [%d]/n", i, j++, k++);

         if(j > 2)

                 exit(0);

          sleep(1);

         longjmp(env, 1);

 

         return 0;

}

[bill@billstone Unix_study]$ make jmp1

cc      jmp1.c    -o jmp1

[bill@billstone Unix_study]$ ./jmp1

setjmp = [0], j = [0], k = [0]

setjmp = [1], j = [1], k = [1]

setjmp = [1], j = [2], k = [2]

[bill@billstone Unix_study]$

   其中 , j 记录了程序的执行次数 按理说 , k 的值应该保持不变 因为当返回到 setjmp 重新执行时 保存的堆栈中 k 应该保持 0 不变 但实际上却变化了 请高手指点 是不是 setjmp 本身实现的问题 ( 我用的环境是 Red Hat 9)?

   单线程 I/O 超时处理

   UNIX 下的 I/O 超时处理是一个很常见的问题 它的通常做法是接收输入 ( 或发送输出 ) 后立刻返回 如果无输入 ( 或输出 ) n 秒后定时返回 .

   一般情况下 处理 UNIX I/O 超时的方式有终端方式 信号跳转方式和多路复用方式等三种 本节设计一个定时 I/O 的例子 它从文件描述符 0 中读取一个字符 当有输入时继续 或者 3 秒钟后超时退出 , 并打印超时信息 .

   (1)  终端 I/O 超时方式

   利用 ioctl 函数 设置文件描述符对应的标准输入文件属性为 接收输入后立刻返回 如无输入则 3 秒后定时返回 .

[bill@billstone Unix_study]$ cat timeout1.c

#include <unistd.h>

#include <termio.h>

#include <fcntl.h>

 

int main()

{

         struct termio old, new;

         char c = 0;

 

         ioctl(0, TCGETA, &old);

         new = old;

         new.c_lflag &= ~ICANON;

         new.c_cc[VMIN] = 0;

         new.c_cc[VTIME] = 30;          //  设置文件的超时时间为 3

         ioctl(0, TCSETA, &new);

         if((read(0, &c, 1)) != 1)

                 printf("timeout/n");

         else

                 printf("/n%d/n", c);

         ioctl(0, TCSETA, &old);

 

         return 0;

}

[bill@billstone Unix_study]$ make timeout1

cc      timeout1.c    -o timeout1

[bill@billstone Unix_study]$ ./timeout1

x

120

[bill@billstone Unix_study]$ ./timeout1

timeout

[bill@billstone Unix_study]$

   (2)  信号与跳转 I/O 超时方式

   read 函数前调用 setjmp 保存堆栈数据并使用 alarm 设定 3 秒定时 .

[bill@billstone Unix_study]$ cat timeout2.c

#include <setjmp.h>

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

 

int timeout = 0;

jmp_buf env;

 

void timefunc(int sig){

         timeout = 1;

         longjmp(env, 1);

}

 

int main()

{

         char c;

 

         signal(SIGALRM, timefunc);

         setjmp(env);

         if(timeout == 0){

                 alarm(3);

                 read(0, &c, 1);

                 alarm(0);

                 printf("%d/n", c);

         }

         else

                 printf("timeout/n");

 

         return 0;

}

[bill@billstone Unix_study]$ make timeout2

cc      timeout2.c    -o timeout2

[bill@billstone Unix_study]$ ./timeout2

v                    //  需要按 Enter 健激活输入

118

[bill@billstone Unix_study]$ ./timeout2

timeout

[bill@billstone Unix_study]$

   (3)  多路复用 I/O 超时方式

   一个进程可能同时打开多个文件 , UNIX 中函数 select 可以同时监控多个文件描述符的输入输出 进程将一直阻塞 直到超时或产生 I/O 为止 此时函数返回 通知进程读取或发送数据 .

   函数 select 的原型如下 :

#include <sys/types.h>

#include <sys/times.h>

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

FD_CLR(int fd, fd_set *fdset);     //  fdset 中删去文件描述符 fd

FD_ISSET(int fd, fd_set *fdset);    //  查询文件描述符是否在 fdset

FD_SET(int fd, fd_set *fdset);      //  fdset 中插入文件描述符 fd

FD_ZERO(fd_set *fdset);         //  清空 fdset

   参数 nfds select 监控的文件描述符的时间 一般为监控的最大描述符编号加 1.

   类型 fd_set 是文件描述符集合 其元素为监控的文件描述符 .

   参数 timeout 是描述精确时间的 timeval 结构 , 它确定了函数的超时时间 , 有三种取值情况 :

   a) NULL.  函数永远等待 直到文件描述符就绪 .

   b) 0.  函数不等待 检查文件描述符状态后立即返回 .

   c)  其他值 函数等待文件描述符就绪 或者定时完成时返回 .

   函数 select 将返回文件描述符集合中已准备好的文件总个数 函数 select 返回就绪文件描述符数量后 必须执行 read 等函数 否则函数继续返回就绪文件数 .

[bill@billstone Unix_study]$ cat timeout3.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/times.h>

#include <sys/select.h>

 

int main()

{

         struct timeval timeout;

         fd_set readfds;

         int i;

         char c;

 

         timeout.tv_sec = 3;

         timeout.tv_usec = 0;

         FD_ZERO(&readfds);

         FD_SET(0, &readfds);

         i = select (1, &readfds, NULL, NULL, &timeout);

         if(i > 0){

                 read(0, &c, 1);

                 printf("%d/n", c);

         }

         else if(i == 0)

                 printf("timeout/n");

         else

                 printf("error/n");

 

         return 0;

}

[bill@billstone Unix_study]$ make timeout3

cc      timeout3.c    -o timeout3

[bill@billstone Unix_study]$ ./timeout3

x

120

[bill@billstone Unix_study]$

[bill@billstone Unix_study]$ ./timeout3

timeout

[bill@billstone Unix_study]$

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值