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,SIGUSR2);
sleep(3);
printf("\n");
printf("屏蔽信号 SIGUSR1 和 SIGUSR2\n");
sigprocmask(SIG_BLOCK,&oldmask);
kill(getpid(),SIGUSR2);
return 0;
}
/*****************************************
包含头文件: #include <signal.h>
函数原型: int sigpending(sigset_t *set);
函数说明: 返回信号集,对于调用进程而言,其中的信号是阻塞不能递送的,因而也一定是当前未决的.
返回值: 若成功,返回-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",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,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,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,&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,&mask1,NULL);
if (sigsuspend(&mask2) != -1)
{
printf("sigsuspend error\n");
exit(0);
}
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,&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,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,NULL) < 0)
return -1;
if (sigaction(SIGQUIT,&savequit,NULL) < 0)
return -1;
if (sigprocmask(SIG_SETMASK,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未休眠完时间长度
返回值:若休眠到要求的时间,返回-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",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;
}