APUE第十章学习笔记

来源:互联网 发布:城管打人 知乎 编辑:程序博客网 时间:2024/06/04 19:02

1.信号

/*****************************************信号处理方式:(1):忽略此信号。(SIGKILL 和 SIGSTOP信号不能被忽略)(2):捕捉信号(3):执行系统默认动作*****************************************//*****************************************包含头文件       #include <signal.h>函数原型:   void (*signal(int signo,void(*func)(int)))(int);函数说明:signo是信号名,func的值是常量 SIG_IGN(忽略)  SIG_DEL(系统默认动作) 或 当接到此信号后要调用的函数地址返回值:若成功,返回以前的信号处理配置,若出错,返回SIG_ERR*****************************************//****************************************exec函数将原先设置为要捕捉的信号都更改为默认动作,其他信号的状态则不变(一个进程原先要捕捉的信号,当其执行一个新程序后,就不能再不捕捉了)子进程会继承父进程信号处理方式*****************************************/

vi 10.1.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>static void sig_usr(int);int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("signal error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("signal error\n");    exit(0);    }    for (; ;)    pause();    return 0;}static void sig_usr(int signo){    if (signo == SIGUSR1)    printf("received SIGUSR1\n");    else if (signo == SIGUSR2)    printf("received SIGUSR2\n");    else    {    printf("received signal %d\n",signo);    exit(0);    }}

这里写图片描述

vi 10.2.c

include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>static void sig_usr(int);int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("1:  signal error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("2: signal error\n");    exit(0);    }    pid_t pid;    if ((pid = fork()) < 0)    {    printf("fork error\n");    exit(0);    }    else if (pid == 0)    {    printf("子进程 ID: %d\n",getpid());    for (; ;)        pause();    }    else    {    printf("父进程 ID: %d\n",getpid());    for (; ;)        pause();    }    return 0;}static void sig_usr(int signo){    if (signo == SIGUSR1)    printf("reveived SIGUSR1\n");    else if (signo == SIGUSR2)    printf("received SIGUSR2\n");    else    {    printf("received signo %d\n",signo);    exit(0);

这里写图片描述

2.可重入函数

/*****************************************可重入函数: 在信号处理程序中保证调用安全的函数,这些函数是可重入的并称为异步信号安全的不可重入函数一般有以下性质:(1):已知它们使用静态数据结构(2):它们调用malloc和free(3):它们是标准I / O函数*****************************************//*****************************************当一个信号产生时,内核在进程表以某种形式设置一个标志,此时为向进程递送一个信号,在信号产生和递送之间的时间间隔内,称信号是未决的如果进程产生了一个阻塞的信号,而且对该信号的动作是系统默认动作或捕捉该信号,则为该进程将此信号保持为未决状态,直到该进程对此信号解除了阻塞,或者将对此信号动作改成忽略*****************************************/

vi 10.3.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <pwd.h>#include <string.h>#include <unistd.h>static void my_alarm(int signo){    struct passwd* rootptr;    printf("in signal handler\n");    if ((rootptr = getpwnam("root")) == NULL)    {    printf("getpwname(root) error\n");    exit(0);    }    alarm(1);}int main(){    struct passwd* ptr;    signal(SIGALRM,my_alarm);    alarm(1);    for (; ;)    {    if ((ptr = getpwnam("marco")) == NULL)    {        printf("getpwnam error\n");        exit(0);    }    if (strcmp(ptr->pw_name,"marco") != 0)    {        printf("return value corrupted!,pw_name = %s\n",ptr->pw_name);    }    }    return 0;}

这里写图片描述

函数 kill 和 raise

/********************************************************包含头文件:  #include <signal.h>函数原型:   int kill(pid_t pid,int signo);            int raise(int signo);函数说明: kill将信号发送给进程或进程组            raise函数则允许进程自身发送信号kill: (1):若pid > 0,则发送signo至进程pid     (2):   若pid == 0,则发送至同一进程组的所有进程(不包括实现的系统进程集)     (3):   若 pid < 0,将该信号发送给进程组等于pid绝对值的所有进程(不包括实现的系统进程集)    (4): 若pid == -1,将该信号发送给发送进程有权限发送的所有进程(不包括实现的系统进程集)raise: 允许进程向自身发送信号返回值:若成功,返回0,若出错,返回-1***********************************************************/

vi 10.4.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>static void sig_usr(int signo){    if (signo == SIGUSR1)    printf("进程 %d 收到信号  SIGUSR1\n",getpid());    else if (signo == SIGUSR2)    printf("进程 %d 收到信号  SIGUSR2\n",getpid());    else    printf("进程 %d 收到信号  %d\n",getpid(),signo);}int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("1: signal error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("2:  signal error\n");    exit(0);    }    pid_t pid;    if ((pid = fork()) < 0)    {    printf("fork error\n");    exit(0);    }    else if (pid == 0)    {    printf("子进程组ID:  %d\n",getpgrp());    pid_t pid2;    if ((pid2 = fork()) < 0)    {        printf("child fork error\n");        exit(0);    }    else if (pid2 == 0)    {        printf("子进程子进程组ID: %d\n",getpgrp());        pause();        pause();        exit(0);    }    sleep(4);    pause();    pause();    exit(0);    }    sleep(6);    printf("父进程进程组ID:  %d\n",getpgrp());    kill(0,SIGUSR1);    kill(0,SIGUSR2);    return 0;}

这里写图片描述

/*******************************************************包含头文件:  #include <unistd.h>函数原型:   unsigned int alarm(usigned int seconds);函数说明:   参数seconds的值是产生信号SIGALRM需要经过时钟秒数每个进程只能有一个闹钟时间.如果在调用alarm时,之前已为该进程注册的闹钟时间还没有超时,则将该闹钟时间的余留值作为本次alarm函数调用的值返回,以前注册的闹钟被新值代替返回值: 0 或 以前设置的闹钟时间的余留秒数********************************************************//*******************************************************包含头文件:  #include <unistd.h>函数原型:   int pause(void);函数说明:使调用进程挂起直至捕捉到一个信号返回值:    -1,errno设置为 EINTR********************************************************/

vi 10.5.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>static void sig_alarm(int signo){}unsigned int sleep1(unsigned int seconds){    if (signal(SIGALRM,sig_alarm) == SIG_ERR)    return seconds;    alarm(seconds);    pause();    return alarm(0);}int main(){   sleep1(5);    return 0;}

vi 10.5.1.c

#include <stdio.h>#include <stdlib.h>#include <setjmp.h>#include <signal.h>#include <unistd.h>static jmp_buf env_alrm;static void sig_alarm(){    longjmp(env_alrm,1);}unsigned int sleep2(unsigned int seconds){    if (signal(SIGALRM,sig_alarm) == SIG_ERR)    return seconds;    if (setjmp(env_alrm) == 0)    {    alarm(seconds);    pause();    }    return (alarm(0));}int main(){    sleep2(5);    return 0;}

3.信号集

/*******************************************************包含头文件:  #include <signal.h>函数原型:   int sigemptyset(sigset_t *set);            int sigfillset(sigset_t  *set);            int sigaddset(sigset_t *set,int signo);            int sigdelset(sigset_t *set,int signo);            int sigismember(const sigset_t *set,int signo);函数说明: sigemptyset 清除所有信号            sigfillset 初始化所有信号            sigaddset 增加特定信号            sigdelset  删除特定信号            sigismember 判断特定信号是否存在于信号集返回值: sigemptyset sigfillset sigaddset sigdelset若成功,返回0,若出错,返回-1sigismember 返回值: 若真,返回 1,若假,返回0*******************************************************//**********************************************************包含头文件:  #include <signal.h>函数原型:   int sigprocmask(int how,const sigset_t* restrict set,sigset_t *restrict oset);函数说明:若set为空,则进程信号屏蔽字则通过oset返回若set非空,则通过how来指示如何修改当前信号屏蔽字how:  SIG_BLOCK 取set 和 oset并集作为当前信号屏蔽字SIG_UNBLOCK  取set 和 oset并集并解除set作为当前信号屏蔽字SIG_SETMASK  将set值作为当前信号屏蔽字注:在调用sigprocmask后如果有任何未决的,不再阻塞的信号,则在sigprocmask返回前,至少将其中之一递送给该进程***************************************************/

vi 10.6.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>void sig_usr(int signo){    if (signo == SIGUSR1)    printf("收到信号  SIGUSR1\n");    else if (signo == SIGUSR2)    printf("收到信号  SIGUSR2\n");    else    printf("收到信号  %d\n",signo);}int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("signal error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("signal error\n");    exit(0);    }    sigset_t oldmask,newmask;    if (sigemptyset(&oldmask) < 0 || sigemptyset(&newmask))     {    printf("sigemptyset error\n");    exit(0);    }    sigaddset(&oldmask,SIGUSR1);    printf("屏蔽信号 SIGUSR1\n");    sigprocmask(SIG_SETMASK,&oldmask,NULL);    kill(getpid(),SIGUSR1);    kill(getpid(),SIGUSR2);    sleep(3);    printf("\n");    printf("屏蔽信号 SIGUSR2\n");    sigaddset(&newmask,SIGUSR2);    sigprocmask(SIG_SETMASK,&newmask,NULL);    kill(getpid(),SIGUSR1);    kill(getpid(),SIGUSR2);    sleep(3);    printf("\n");    printf("屏蔽信号 SIGUSR1 和 SIGUSR2\n");    sigprocmask(SIG_BLOCK,&newmask,&oldmask);    kill(getpid(),SIGUSR1);    kill(getpid(),SIGUSR2);    return 0;}

这里写图片描述

/*****************************************包含头文件:  #include <signal.h>函数原型:   int sigpending(sigset_t  *set);函数说明:   返回信号集,对于调用进程而言,其中的信号是阻塞不能递送的,因而也一定是当前未决的.返回值: 若成功,返回0,若出错,返回-1*****************************************/

vi 10.7.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>void sig_usr(int signo){    if (signo == SIGUSR1)    printf("收到信号  SIGUSR1\n");    else if (signo == SIGUSR2)    printf("收到信号  SIGUSR2\n");    else    printf("收到信号  %d\n",signo);}int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("signal error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("signal error\n");    exit(0);    }    sigset_t mask,oldmask;    sigemptyset(&mask);    sigaddset(&mask,SIGUSR1);    //得到row 信号集    sigprocmask(SIG_BLOCK,NULL,&oldmask);    //屏蔽信号 SIGUSR1        sigprocmask(SIG_SETMASK,&mask,NULL);    //发送信号 SIGUSR1    kill(getpid(),SIGUSR1);    // 信号SIGUSR1 阻塞未决    sigset_t getmask;    sigemptyset(&getmask);    sigpending(&getmask);    if (sigismember(&getmask,SIGUSR1))    printf("SIGUSR1 is mask\n");    // 解除屏蔽信号 SIGUSR1    sigprocmask(SIG_SETMASK,&oldmask,NULL);    return 0;}

这里写图片描述

4.sigaction函数

/*****************************************包含头文件:  #include <signal.h>函数原型:   int sigaction(int signo,const struct sigaction *restrict act,struct sigaction * restrict oact);函数说明:参数signo是要检测或修改其具体动作的信号编号,若act非空,则修改其动作,如果oact非空,则系统由oact返回该信号的上一个动作返回值:若成功,返回0,若失败,返回-1strcut sigaction{    void (*sa_handler)(int) ;   //信号处理函数的地址    sigset_t sa_mask;            //增加需要阻塞的信号    int sa_flags;                //可选标志    void (*sa_sigaction)(int,siginfo_t *,void *);//可替代信号处理程序}struct siginfo{    int si_signo;    //信号编号    int si_errno;    //错误标志    int si_code;         //可添加的代码    pid_t si_pid;   //传送进程ID    uid_t si_uid;   //传送进程实际用户ID    void *si_addr;  //造成错误的地址    int si_status;    //退出值或信号值    union sigval si_value; //应用程序特殊值 /* ………….. */};union sigval{    int sival_int;    void* sival_ptr;};*****************************************/

vi 10.8.c

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>void sig_usr(int signo){    if (signo == SIGUSR1)    printf("收到信号 SIGUSR1\n");    else if (signo == SIGUSR2)    printf("收到信号 SIGUSR2\n");    else    printf("收到信号 %d\n",signo);}int main(){    struct sigaction act;    act.sa_handler = sig_usr;    if (sigaction(SIGUSR1,&act,NULL) < 0)    {    printf("sigaction error\n");    exit(0);    }    if (sigaction(SIGUSR2,&act,NULL) < 0)    {    printf("sigaction error\n");    exit(0);    }    kill(getpid(),SIGUSR1);    kill(getpid(),SIGUSR2);    return 0;}

这里写图片描述

vi 10.9.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>typedef void Sigfunc(int);Sigfunc * signal2(int signo,Sigfunc *func){    struct sigaction act,oact;    act.sa_handler = func;    sigemptyset(&act.sa_mask);    act.sa_flags = 0;    if (signo == SIGALRM)    {#ifdef SA_INTERRUPT    act.sa_flags |= SA_INTERRUPT;#endif    }    else    {    act.sa_flags |= SA_RESTART;    }    if (sigaction(signo,&act,&oact) < 0)    return (SIG_ERR);    return (oact.sa_handler);}void sig_usr(int signo){    if (signo == SIGUSR1)    printf("接收到信号 SIGUSR1\n");    else    printf("接收到信号  %d\n",signo);}int main(){    if (signal2(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("signal2 error\n");    exit(0);    }    kill(getpid(),SIGUSR1);    return 0;}

这里写图片描述

4.sigsetjmp 和 siglongjmp函数

/**********************************************************包含头文件:  #include <setjmp.h>函数原型:   int sigsetjmp(sigjmp_buf env,int savemask);函数说明:   进行非局部转移并恢复所保存信号屏蔽字返回值:若直接调用,返回0;若从siglongjmp调用返回,则返回非0void siglongjmp(sigjmp_buf env,int val);*********************************************************/

这里写图片描述

5.sigsuspend函数

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>void sig_usr1(int signo){    printf("接收到信号 SIGUSR1\n");}void sig_usr2(int signo){    printf("接收到信号 SIGUSR2\n");}int main(){    if (signal(SIGUSR1,sig_usr1) == SIG_ERR)    {    printf("signal SIGUSR1 error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr2) == SIG_ERR)    {    printf("signal SIGUSR2 error\n");    exit(0);    }    sigset_t mask1,mask2;    sigemptyset(&mask1);    sigemptyset(&mask2);    sigaddset(&mask1,SIGUSR1);    sigaddset(&mask2,SIGUSR2);    sigprocmask(SIG_SETMASK,&mask1,NULL);    if (sigsuspend(&mask2) != -1)    {    printf("sigsuspend error\n");    exit(0);    }    kill(getpid(),SIGUSR1);    kill(getpid(),SIGUSR2);    return 0;}

这里写图片描述

6.函数system

vi 10.12.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>#include <errno.h>#include <sys/wait.h>int system1(const char* cmdstring){    if (cmdstring == NULL)    return 1;    struct sigaction ignore,saveintr,savequit;    sigset_t chldmask,savemask;    ignore.sa_handler = SIG_IGN;    sigemptyset(&ignore.sa_mask);    ignore.sa_flags = 0;    if (sigaction(SIGINT,&ignore,&saveintr) < 0)    {    return -1;    }    if (sigaction(SIGQUIT,&ignore,&savequit) < 0)    {    return -1;    }    sigemptyset(&chldmask);    sigaddset(&chldmask,SIGCHLD);    if (sigprocmask(SIG_BLOCK,&chldmask,&savemask) < 0)    return -1;    pid_t pid;    int status;    if ((pid = fork()) < 0)    status = -1;    else if (pid == 0)    {    sigaction(SIGINT,&saveintr,NULL);    sigaction(SIGQUIT,&saveintr,NULL);    sigprocmask(SIG_SETMASK,&savemask,NULL);    execl("/bin/sh","sh","-c",cmdstring,(char*)0);    _exit(127);    }    else    {    while (waitpid(pid,&status,0) < 0)        if (errno == EINTR)        {        status = -1;        break;        }    }    if (sigaction(SIGINT,&saveintr,NULL) < 0)    return -1;    if (sigaction(SIGQUIT,&savequit,NULL) < 0)    return -1;    if (sigprocmask(SIG_SETMASK,&savemask,NULL) < 0)    return -1;    return status;}int main(){    system1("date");    return 0; }

这里写图片描述

7.nanosleep

/**********************************************************包含头文件:  #include <time.h>函数原型:   int nanosleep(const struct timespec *reqtp,struct timespec *remtp);函数说明:挂起调用进程,直到要求时间超时或某个信号中断了该函数,reqtp指向休眠长度,remtp未休眠完时间长度返回值:若休眠到要求的时间,返回0,若出错,返回-1**********************************************************//***********************************************************包含头文件:  #include <time.h>函数原型:   int clock_nanosleep(clockid_t clock_id,int flags,const struct timespec* reqtp,struct timespec* remtp);函数说明:   flags为0表示休眠时间是相对的,表示休眠reqtp时间,flags为 TIMER_ABSTIME,表示休眠时间是绝对的,表示休眠到reqtp**********************************************************/

vi 10.13.c

#include <time.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>struct timespec* rest = NULL; void sig_usr(int signo){    if (rest != NULL)    {    printf("剩于未休眠时间  秒数: %ld  纳秒数: %ld\n",rest->tv_sec,rest->tv_nsec);    }}int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("signal SIGUSR1 error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("signal SIOGUSR2 error\n");    exit(0);    }    struct timespec set;    set.tv_sec = 20;    set.tv_nsec = 0;    rest = (struct timespec*)(malloc(sizeof(struct timespec)));    nanosleep(&set,rest);    return 0;}

这里写图片描述

vi 10.14.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <time.h>struct timespec* rest = NULL;void sig_usr(int signo){    if (rest != NULL)    {    printf("休眠剩余时间:  秒数: %ld  纳秒数: %ld\n",rest->tv_sec,rest->tv_nsec);    }}int main(){    if (signal(SIGUSR1,sig_usr) == SIG_ERR)    {    printf("signal SIGUSR1 error\n");    exit(0);    }    if (signal(SIGUSR2,sig_usr) == SIG_ERR)    {    printf("signal SIGUSR2 error\n");    exit(0);    }    struct timespec set;    clock_gettime(CLOCK_REALTIME,&set);    set.tv_sec += 40;    rest = (struct timespec *)malloc(sizeof(struct timespec));    clock_nanosleep(CLOCK_REALTIME,TIMER_ABSTIME,&set,rest);    return 0;}

这里写图片描述

8.sigqueue函数

/***********************************************************包含头文件:  #include <signal.h>函数原型: int sigqueue(pid_t pid,int signo,const union sigval value);函数说明:将信号发给单个进程,并附带value所传递值***********************************************************/

vi 10.15.c

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <unistd.h>void usr1_handler(int signo,siginfo_t *siginfo,void* context){    printf("接收到信号 SIGUSR1\n");    printf("接收到附加信息是 %s\n",(char*)(siginfo->si_value.sival_ptr));}int main(){    struct sigaction usr1act;    usr1act.sa_sigaction = usr1_handler;    usr1act.sa_flags = SA_SIGINFO;    sigemptyset(&usr1act.sa_mask);    if (sigaction(SIGUSR1,&usr1act,NULL) < 0)    {    printf("sigaction SIGUSR1 error\n");    exit(0);    }    union sigval value;    value.sival_ptr = "SIGUSR1 的附加信息\n";     if (sigqueue(getpid(),SIGUSR1,value) < 0)    {    printf("sigqueue error\n");    exit(0);     }    return 0;}

这里写图片描述