zoukankan      html  css  js  c++  java
  • 三十三、Linux 进程与信号——中断系统调用和函数可重入性

    33.1 中断系统调用

    • 进程调用 “慢” 系统调用时,如果发生了信号,内核会重启系统调用。
    • 慢系统调用
      • 可能会永久阻塞的系统调用
      • 从终端设备、管道或网络设备上的文件读取
      • 向上述文件写入
      • 某些设备上的文件打开
      • pause 和 wait 系统调用
      • 一些设备的 ioctl 操作
      • 一些进程间通信函数

    33.1.1 慢系统调用引起的调用重启

     1 #include <unistd.h>
     2 #include <signal.h>
     3 #include <stdio.h>
     4 #include <stdlib.h>
     5 
     6 
     7 void sig_handler(int signo)
     8 {
     9     if(signo == SIGTSTP){
    10         printf("SIGTSTP occured
    ");
    11     }
    12 }
    13 
    14 int main(void)
    15 {
    16     char buffer[512];
    17     ssize_t size;
    18 
    19     if(signal(SIGTSTP, sig_handler) == SIG_ERR){
    20         perror("signal sigtstp error");
    21     }
    22 
    23     printf("begin running and waiting for signal
    ");
    24     size = read(STDIN_FILENO, buffer, 512);
    25     if(size < 0){
    26         perror("read error");
    27     }
    28 
    29     printf("reading finished
    ");
    30 
    31     if(write(STDOUT_FILENO, buffer, size) != size) {
    32         perror("write error");
    33     }
    34     printf("end running
    ");
    35     return 0;
    36 }

    33.1.2 自定义函数

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <signal.h>
     4 #include <unistd.h>
     5 
     6 void sig_handler(int signo)
     7 {
     8     if(signo == SIGTSTP){
     9         printf("SIGTSTP occured
    ");
    10     }
    11 }
    12 
    13 void call_fun(void)
    14 {
    15     printf("begin running call_fun
    ");
    16     sleep(10);
    17     printf("end running call_fun
    ");
    18 }
    19 
    20 int main()
    21 {
    22     if(signal(SIGTSTP, sig_handler) == SIG_ERR){
    23         perror("signal sigtstp error");
    24     }
    25 
    26     printf("begin running main
    ");
    27     call_fun();
    28     printf("end running main
    ");
    29 }

    33.2 函数可重入性

    • 在调用某个函数过程中出现信号,且该信号处理函数中再次调用该函数
      • 访问全局或静态变量的函数是不可重入函数
        • 即前后数据不一致
      • 若是函数内部的局部变量,则此函数是可重入函数
        • 即前后数据一致
    • 程序片段如下:

      

     1 #include <signal.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 
     6 int g_v[10];
     7 int *h_v;    ///< 堆中变量
     8 
     9 void set(int val)
    10 {
    11     int a_v[10];
    12 
    13     int i = 0;
    14     for(; i < 10; i++) {
    15         a_v[i] = val;
    16         g_v[i] = val;
    17         h_v[i] = val;
    18         sleep(1);
    19     }
    20 
    21     printf("g_v:");
    22     for(i = 0; i < 10; i++){
    23         if(i != 0) {
    24             printf(", %d", g_v[i]);
    25         }
    26         else {
    27             printf(", %d", g_v[i]);
    28         }
    29     }
    30     printf("
    ");
    31 
    32     printf("h_v:");
    33     for(i = 0; i < 10; i++){
    34         if(i != 0) {
    35             printf(", %d", h_v[i]);
    36         }
    37         else {
    38             printf(", %d", h_v[i]);
    39         }
    40     }
    41 
    42     printf("
    ");
    43     printf("a_v:");
    44     for(i = 0; i < 10; i++){
    45         if(i != 0) {
    46             printf(", %d", a_v[i]);
    47         }
    48         else {
    49             printf(", %d", a_v[i]);
    50         }
    51     }
    52 }
    53 
    54 void sig_handler(int signo)
    55 {
    56     if(signo == SIGTSTP){
    57         printf("SIGTSTP occured
    ");
    58         set(20);
    59         printf("
    end SIGTSTP
    ");
    60     }
    61 }
    62 int main(void)
    63 {
    64     if(signal(SIGTSTP, sig_handler) == SIG_ERR){
    65         perror("signal sigtstp error");
    66     }
    67 
    68     h_v = (int *)calloc(10, sizeof(int));
    69 
    70     printf("begin running main
    ");
    71     set(10);
    72     printf("
    end running main
    ");
    73     return 0;
    74 }

      运行结果:

      

      全局变量中的数据不可控,局部变量都为 10

      第一次调用 set 函数的时候,set(10) 中的循环运行了 2 次,此时 i = 2,然后中断,再次运行set(20) 函数,此时将所有变量中的值覆盖掉了,中断完了之后,函数继续从中断的地方运行,此时中断的地方 i = 2,则全局变量和堆变量从此处开始运行,后面的 20 都被 10 给覆盖。

  • 相关阅读:
    手游页游和端游的服务端的架构与区别
    TiKV 源码解析系列——如何使用 Raft
    TiKV 源码解析系列
    三篇文章了解 TiDB 技术内幕 —— 谈调度
    三篇文章了解 TiDB 技术内幕——说计算
    三篇文章了解 TiDB 技术内幕——说存储
    TiDB 源码阅读系列文章(一)序
    【合集】TiDB 源码阅读系列文章
    9个offer,12家公司,35场面试,从微软到谷歌,应届计算机毕业生的2012求职之路
    python datetime和unix时间戳之间相互转换
  • 原文地址:https://www.cnblogs.com/kele-dad/p/10152078.html
Copyright © 2011-2022 走看看