APUE第十章学习笔记

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 
#include 
#include 
#include 

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);
    }
}

APUE第十章学习笔记_第1张图片

vi 10.2.c

include 
#include 
#include 
#include 

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);

APUE第十章学习笔记_第2张图片

2.可重入函数

/*****************************************
可重入函数: 在信号处理程序中保证调用安全的函数,这些函数是可重入的并称为异步信号安全的
不可重入函数一般有以下性质:
(1):已知它们使用静态数据结构
(2):它们调用malloc和free
(3):它们是标准I / O函数
*****************************************/

/*****************************************
当一个信号产生时,内核在进程表以某种形式设置一个标志,此时为向进程递送一个信号,在信号产生和递送之间的时间间隔内,称信号是未决的
如果进程产生了一个阻塞的信号,而且对该信号的动作是系统默认动作或捕捉该信号,则为该进程将此信号保持为未决状态,直到该进程对此信号解除了阻塞,或者将对此信号动作改成忽略
*****************************************/

vi 10.3.c

#include 
#include 
#include 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第3张图片

函数 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 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第4张图片

/*******************************************************
包含头文件:  #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 
#include 
#include 
#include 

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 
#include 
#include 
#include 
#include 


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,若出错,返回-1
sigismember 返回值: 若真,返回 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 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第5张图片

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

vi 10.7.c

#include 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第6张图片

4.sigaction函数

/*****************************************
包含头文件:  #include <signal.h>
函数原型:   int sigaction(int signo,const struct sigaction *restrict act,struct sigaction * restrict oact);
函数说明:参数signo是要检测或修改其具体动作的信号编号,若act非空,则修改其动作,如果oact非空,则系统由oact返回该信号的上一个动作
返回值:若成功,返回0,若失败,返回-1

strcut 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 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第7张图片

vi 10.9.c

#include 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第8张图片

4.sigsetjmp 和 siglongjmp函数

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

void siglongjmp(sigjmp_buf env,int val);
*********************************************************/

APUE第十章学习笔记_第9张图片

5.sigsuspend函数

#include 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第10张图片

6.函数system

vi 10.12.c

#include 
#include 
#include 
#include 
#include 
#include 

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;
 }

APUE第十章学习笔记_第11张图片

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 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第12张图片

vi 10.14.c

#include 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第13张图片

8.sigqueue函数

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

vi 10.15.c

#include 
#include 
#include 
#include 

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;
}

APUE第十章学习笔记_第14张图片

你可能感兴趣的:(APUE)