UNIX_C 高级编程<四>

 #include <sys/types.h>

     #include <unistd.h>

 

     pid_t vfork(void);

        

         功能:用于创建当前正在调用进程的子进程,返回值以及可能出现的错误参考fork函数即可

              vfork函数在创建子进程时,不会复制父进程中的内存空间信息   

              vfork函数不同于fork函数,会挂起父进程的执行,直到子进程终止或调用exec系列函数为止

              vfork函数创建的子进程会共享所有内存空间和他父进程,包括栈区,该子进程在终止时不

                +能从当前函数return或着调用exit()函数,可以直接调用_exit()函数

              vfork函数保证了子进程先执行

 

     exec系列函数

 

    #include <unistd.h>

 

    extern char **environ;

 

    int execl(const char *path, const char*arg, ...);

    

         参 1:字符串形式的文件路径名

         参 2:字符串形式的参数,一般给文件的执行方式

         参 3:可变长参数,给NULL表示结尾

    

         返回:只有出错时才有返回值,返回值为-1;

         功能:主要用于执行参数指定的文件;                

        

              eg:execl("/bin/ls", "ls", "-l", NULL);

 

         注意:vfork函数本身并没有太大的实际意义,一般和exec系列的函数搭配使用,主要用于

              +子进程执行和父进程完全不同代码段的场合中;

 

              fork函数也可以和exec系列函数搭配使用,只是fork函数可能会复制父进程中除了代码区

                   +之外的其它内存区域,因此执行效率比较低(写时拷贝技术)

 

     #include <stdlib.h>

 

     intsystem(const char *command);

 

         返回:成功返回命令的状态信息,可以通过WEXITSTATUS进行解析, 失败 —— -1  

         功能:执行参数指定的shell命令

 

        

中断的概念和分类

 

     中断就是停止当前正在执行的进程转而去执行新的进程或者处理意外情况的过程;

 

     中断分为两种:硬件中断和软件中断

 

信号处理

 

     信号本质就是一种软件中断,它既可以作为两个进程间的通信方式,也可以终止一个正常

         +执行的程序,它更多地被用于处理意外情况;

 

     a.信号是异步的,也就是进程并不知道信号何时到达

     b.进程既可以发送信号,也可以处理信号

     c.每个信号都有一个名字,并且用SIG开头

 

     kill -l 表示查看当前系统所支持的所有信号

        

              SIGINT   2  使用ctrl+c来产生信号    终止进程

            SIGQUIT  3  使用ctrl+\来产生信号 终止进程

            SIGKILL 9   使用kill -9来产生信号   终止进程

    

     在当前教学系统,支持的信号范围是:1~64,

         其中1~31之间的信号叫做不可靠信号,不支持排队信号可能会丢失,也叫做非实时信号;

         其中34~64之间的信号叫做可靠信号,支持排队,信号不会丢失,也叫做实时信号;

 

信号处理的方式

 

     1.默认处理,绝大多是信号的默认处理方式都是终止进程

     2.忽略处理

     3.自定义处理

 

      #include <signal.h>

     typedef void (*sighandler_t)(int);  =>   typedef void(*)(int) sighandler_t;       

     sighandler_tsignal(int signum, sighandler_t handler);

 

     => signal是一个函数,有两个参数,一个是int类型,一个是函数指针类型返回值类型也是一个函数指针类型

 

     函数功能解析:

         参 1:信号值/信号名称(设置那个信号)

         参 2:具体的处理方式(设置怎么处理)

                   a.SIG_IGN - 忽略处理

                b.SIG_DFL - 默认处理

                c.自定义函数的地址 - 自定义处理

         返回:成功返回之前的处理方式,失败返回SIG_ERR

         功能:主要用于设置指定信号处理的方式

        

     父进程对信号处理方式的比较

         1.对于fork函数创建的子进程来说,对信号处理方式完全照搬父进程,也就是父进程自定义子进程也自定义处理,父进程忽略处理,子进程也忽略处理,父进程默认处理,子进程也默认处理

         2.对与vfork函数和execl函数启动了子进程来说,父进程忽略处理,子进程也忽略,父进程默认处理,子进程也默认处理;父进程自定义处理时,子进程采用默认处理;

                                      

     发送信号的主要方式

    

         1.采用键盘发送信号(只能发送部分特殊的信号)

              SIGINT 2 => 使用ctrl+c发送信号

        

         2.由程序出错发送信号(只能发送部分特殊的信号)

              SIGSEGV 11 => 段错误发送信号

 

         3.使用kill命令发送信号(发送所有信号)

              kill -信号值/信号名称 进程号

 

         4.采用系统函数发送信号(取决于函数的功能)

              kill()/raise()/alarm()/sigqueue()

 

      #include <sys/types.h>

      #include <signal.h>

 

      int kill(pid_t pid, int sig);

         参 1:进程的编号(给谁发信号)

                   >0 表示发送信号sig给进程号为pid的进程(重点)

                   =0   表示发送信号sig给和当前调用进程在同一个进程组的每一进程

                   =-1  表示发送信号sig给每一个当前前进程拥有发送信号权限的进程,除了进程inti(1)

                   <-1  表示发送信号sig给进程组ID 为-PID的每一个进程

         参 2:信号值/信号名称(发送什么样的信号)

                   =0  表示不会发送信号,主要用于检查第一个参数进程/进程组是否存在

         功能:主要用于给指定的进程发送指定的信号

 

 

    

     int raise(int sig);

 

         功能:主要用于给当前正在调用的进程或线程发送参数指定的信号,对与单线程的程序来说,等价于Kill(getpid(), sig)

         返回:成功 —— 0, 失败 —— !0

 

     unsigned int sleep(unsigned int seconds);

 

功能:用于让当前正在调用的线程睡眠参数指定的秒数,直到参数指定的秒数过去了或者一个不能忽略的信号到达时线程会被唤醒

返回:参数指定的秒数睡够了则返回0,否则返回没来的及睡眠的秒数/剩余秒数

    

     unsigned int alarm(unsigned int seconds);

 

         功能:主要用于经过参数指定的秒数后给当前正在调用的进程发送SIGALRM信号

                每次使用alarm设置新的闹钟时,都会取消之前的闹钟,当参数为0时主要用于取消所有闹钟

         返回:如果之前没有闹钟返回0,否则返回之前闹钟剩余的秒数

 

   int sigqueue(pid_t pid, int sig, const union sigval value);

         参 1:进程的编号

         参 2:信号值/信号名称

         参 3:联合类型的附加数据

         功能:主要用于给参数指定的进程发送信号和附加数据

               union sigval {

               int   sival_int;

               void *sival_ptr; ==NULL

           };


信号集的概念和操作

 

     信号集本质就是由若干个信号组成的集合

     信号集的数据类型:sigset_t类型

 

              typedef struct

              {

                   unsigned long int __val[ (1024 / (8 *sizeof (unsigned long int))) ];

              }__sigset_t;

              typedef __sigset_tsigset_t;

 

     #include <signal.h>

 

    int sigemptyset(sigset_t *set); —— 清空

    int sigfillset(sigset_t *set);   —— 填满

    int sigaddset(sigset_t *set, int signum);    —— 添加

    int sigdelset(sigset_t *set, int signum);    —— 删除

    int sigismember(const sigset_t *set, intsignum);    —— 判断是否存在

 

信号的屏蔽

     在某些特殊程序的执行过程中,是不允许被信号打断的,这种情况下需要使用信号的屏蔽来实现

     #include<signal.h>

     int sigprocmask(int how, const sigset_t*set, sigset_t *oldset);

 

         参 1:信号的屏蔽方式(怎么样屏蔽)

                   SIG_BLOCK - 当前屏蔽集合 + 参数 set 结合(ABC +CDE = ABCDE)

                   SIG_UNBLOCK - 当前屏蔽集合 - 参数 set 结合(ABC -CDE = AB)

                   SIG_SETMASK - 参数 set 集合 替换 当前屏蔽集合(ABC CDE => CDE)

         参 2:信号集类型的指针,用于指定新的屏蔽集

         参 3:信号集类型的指针,不为空时, 带出之前的信号屏蔽集

 

         功能:主要用于检查和修改屏蔽的信号集

        

         注意:信号屏蔽并不是删除信号,而是将信号屏蔽期间来过的信号,保存起来,等信号屏蔽解除之后还是会处理,

对于可靠信号来说,来多少保存多少,对于不可靠信号,只保存一份;

   

     int sigpending(sigset_t *set);

             

         功能:主要用于获取信号屏蔽期间产生但没有来的及处理的信号集,通过参数指针带出去

 

//sigprocmask函数的使用

  2

  3 #include <stdio.h>

  4 #include <stdlib.h>

  5 #include <unistd.h>

  6 #include <sys/types.h>

  7 #include <signal.h>

  8

  9 void fa(int signum)

 10 {

 11 // printf("捕获到了信号%d\n", signum);

 12 }

 13

 14 int main(void)

 15 {

 16    //1.打印当前进程的编号

 17        printf("pid=%d\n", getpid());

 18    //2.设置信号2,3,50进行自定义处理

 19        if( SIG_ERR == signal(2, fa) )

 20        {

 21            perror("signal");

 22            exit(1);

 23        }

 24        if( SIG_ERR == signal(3, fa) )

 25        {

 26            perror("signal");

 27            exit(1);

 28        }

 29        if( SIG_ERR == signal(50, fa))

 30        {

 31            perror("signal");

 32            exit(1);

 33        }

 34    //3.是的当前进程睡眠20秒等待信号到来

 35

 36        int res = sleep(20);

 37        if( 0 == res )

 38        {

 39            printf("睡了一觉");

 40        }

 41        else

 42        {

 43            printf("没有信号的屏蔽,睡眠被打断,睡了%d秒\n", 20-res);

 44        }

 45

 46        printf("---------------------------------\n");

 47

 48        printf("下面开始设置信号的屏蔽");

 49

 50        //定义两个信号集类型的变量

 51        sigset_t set, old;

 52

 53        //清空两个信号集类型的变了

 54        if( -1 == sigemptyset(&set) )

 55        {

 56            perror("sigemptyset");

 57            exit(-1);

 58        }

 59

 60        if( -1 ==  sigemptyset(&old))

 61        {

 62            perror("sigemptyset");

 63            exit(-1);

 64        }

 65

 66        //增加信号2,3, 50到信号集set中

 67

 68        if(-1 == sigaddset(&set, 2) )

 69        {

 70            perror("sigaddset");

 71            exit(-1);

 72        }

 73        if(-1 == sigaddset(&set, 3) )

 74        {

 75            perror("sigaddset");

 76            exit(-1);

 77        }

 78        if(-1 == sigaddset(&set, 50) )

 79        {

 80            perror("sigaddset");

 81            exit(-1);

 82        }

 83

 84    //设置信号的屏蔽

 85        res = sigprocmask(SIG_SETMASK, &set, &old );

 86        if(-1 == res )

 87        {

 88            perror("sigprocmask");

 89            exit(-1);

 90        }

 91

 92        printf("设置信号屏蔽成功,old = %d \n", old);

 93

 94        res = sleep(20);

 95        if( 0 == res)

 96        {

 97            printf("信号屏蔽成功,休眠完20秒\n");

 98         }

 99        else

100         {

101             printf("产生了没有被屏蔽的信号\n");

102         }

103

104         //获取信号屏蔽期间来过的信号

105

106         sigset_t pend;

107

108         if( -1 == sigemptyset(&pend) )

109         {

110             perror("sigemptyset");

111             exit(-1);

112         }

113

114         if( -1 == sigpending(&pend) )

115         {

116             perror("sigpending");

117             exit(-1);

118         }

119

120         //判断信号2,3,50是否来过

121

122         if( sigismember(&pend,2) > 0 )

123         {

124             printf("信号2来过\n");

125         }

126

127         if( sigismember(&pend,3) > 0 )

128         {

129             printf("信号3来过\n");

130         }

131

132         if( sigismember(&pend,50) > 0 )

133         {

134             printf("信号50来过\n");

135         }

136

137

138         //恢复系统默认的信号屏蔽集

139

140         res = sigprocmask(SIG_SETMASK,&old, NULL);

141         if( -1 == res )

142         {

143             perror("sigprocmask");

144             exit(-1);

145         }

146

147     return 0;

148

149 }

   

 

     int sigaction(int signum, const struct sigaction *act, struct sigaction*oldact);

        

         参 1:信号值/信号名称

         参 2:结构体指针,用于设置信号最新的处理方式

 

                   truct sigaction {

                      void     (*sa_handler)(int); 

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

                      sigset_t   sa_mask;

                      int        sa_flags;

                      void     (*sa_restorer)(void);       //函数指针类型,是一个过时成员,不使用

            };

 

                   成员1:函数指针类型,用于设置对信号处理的方式,取值可以是:SIG_IGN/SIG_DFL/自定义函数地址

                   成员2:功能与成员1相同,但取决于成员4取值为(SA_SIGINFO)

                                 参1:

                                 参2:     siginfo_t {

                                    ……

                                      pid_t      si_pid;       //发送方的进程号   

                                      sigval_t   si_value;     //伴随信号到来的附加数据

                                    ……

                                }       

 

                            参3:不使用NULL

                   成员3:用于设置在信号处理函数执行期间需要屏蔽的信号,自动屏蔽触发信号处理函数的信号,

                            如果成员4值是SA_NODEFER,则不会自动屏蔽触发信号处理函数的信号

                   成员4:SA_SIGINFO表示选择成员2为信号的处理方式

                          SA_NODEFER表示解除对触发信号处理函数的信号的屏蔽(如成员3)

 

    

         参 3:结构体指针,用于带出信号之前的处理方式

         功能:主要用于检查和修改指定信号的处理方式

 

      1 //使用sigaction函数设置对信号的处理方式

      2

      3#include <stdio.h>

      4#include <stdlib.h>

      5#include <unistd.h>

      6#include <sys/types.h>

      7#include <signal.h>

      8

      9void fa ( int signum )

     10 {

     11    printf("正在处理信号,请稍后...\n");

     12    sleep(10);

     13    printf("信号处理完毕\n");

     14

     15 }

     16

     17 int main(void)

     18 {

     19

     20    //准备结构体变量,并初始化

     21    struct sigaction action = {};

     22    action.sa_handler = fa;

     23

     24    //在执行fa函数期间屏蔽函数3

     25

     26    if(-1 == sigemptyset( &action.sa_mask ) )

     27    {

     28        perror("sigemptyset");

     29        exit(-1);

     30    }

     31

     32    if(-1 == sigaddset(&action.sa_mask, 3) )

     33    {

     34        perror("sigaddset");

     35        exit(-1);

 

      1#include <stdio.h>

      2#include <stdlib.h>

      3#include <unistd.h>

      4#include <sys/types.h>

      5#include <signal.h>

      6

      7void fa ( int signum, siginfo_t * info, void * pv)

      8 {

      9    printf("进程%d发来了信号%d\n",info->si_pid, signum);

     10 }

     11

     12 int main(void)

     13 {

     14    //打印当前进程的进程号

     15         printf( "pid = %d\n",getpid() );

     16

     17    //准备结构体变量,并初始化

     18        struct sigaction action = {};

     19

     20    //设置自定义处理

     21        action.sa_sigaction = fa;

     22    //选择第二个函数指针

     23        action.sa_flags = SA_SIGINFO;

     24

     25    //使用sigaction设置对2进行自定义处理

     26

     27    int res = sigaction(2, &action, NULL );

     28    if(-1 == res )

     29    {

     30        perror("sigaction");

     31        exit(1);

     32    }

     33

     34    while(1);

     35

     36    return 0;

     37 }

 

计时器

 

     #include <sys/time.h>

 

    int getitimer(int which, struct itimerval *curr_value);

    int setitimer(int which, const structitimerval *new_value, struct itimerval *old_value);

                                                                              

         参 1:计时器的类型

              ITIMER_REAL - 真实计时器,统计进程消耗的真实时间,定时发送SIGALRM信号

              ITIME_VIRTUAL - 虚拟计时器,统计进程在用户态下消耗的时间

              ITIME_PROF - 实用计时器,统计进程在用户态和内核态消耗的总时间,定时发送SIGPROF信号

 

         参 2:结构体指针,用于设置计时器的新值

              struct itimerval {

               struct timevalit_interval; /* 间隔时间 */

               struct timevalit_value;    /* 启动时间 */

              };

 

           struct timeval {

               long tv_sec;                /* 秒 */

               long tv_usec;               /* 微秒 1 sec = 10^6 user */

           };

 

         参 3:结构体指针,用于带出计时器的旧值

         功能:主要用于获取/设置计数器的数值



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值