您的位置:首页 > 产品设计 > UI/UE

APUE第十章学习笔记

2017-09-25 22:14 309 查看
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,若出错,返回-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 <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,若失败,返回-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 <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调用返回,则返回非0

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


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  APUE UNIX c linux