1.1信号的概念
信号:信号是异步传送给进程的时间通知,进程无法准确地预测合适会出现信号。
同步信号:程序中的某个具体的操作相关并且在那个操作进行的同时产生。
异步信号:进程之外的事件产生的信号。
当信号发生时进程采取的动作:
1)忽略信号。
2)捕获信号。
3)执行系统默认动作。
1.2 kill( )函数
#include <signal.h>
int kill(pid_t pid, int sig);
pid > 0:把信号发送给ID为pid的进程。
pid == 0:把信号发送给进程所在进程组的所有进程。
pid < -1:把发送给ID为pid的绝对值的进程组(发送者有权发送)。
pid == -1:广播信号,发送给发送者有权发送的所有进程。
sig:信号。
执行成功返回0,失败返回-1并且置error指出错误原因。
为了防止随意的杀死属于其他用户的进程,一般发送信号的实际用户ID或有效ID必须与接受信号的实际用户ID或有效ID相同。root用户有权向任意用户发送信号。
使用kill( )函数发送信号的例子:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
int flag = 0; /*标志变量*/
void sig_usr(int sig) /*信号句柄*/
{
flag = 1;
}
void child() /*子进程调用,发送给父进程SIGUSR1信号*/
{
printf("My Pid is %d \n",(int)getpid());
kill(getppid(),SIGUSR1);
printf("life over!\n");
exit(0);
}
int main()
{
pid_t ch;
signal(SIGUSR1,sig_usr); /*设置信号动作*/
if((ch = fork()) == -1) /*如果创建子进程失败,退出*/
{
fprintf(stderr,"faild!\n");
exit(-1);
}
if(ch == 0) /*如果是子进程*/
child();
while(!flag); /*循环等待SIGUSR1信号的出现*/
fprintf(stdout,"voer!\n");
return 0;
}
1.3设置信号动作
#include <signal.h>
typedef void (*sighandler_t) (int);
sighandler_t signal(int signum,sighandler_t handler);
signum:指明是那种信号。
handler:信号发生时应该采取的动作。
返回值:前一次有效动作的指针。
signal的缺陷:
void sig_usr(int sig)
{
.......
signal(SIGUSR1 sig_usr); /*设置SIGUSR1信号句柄*/
}
int main()
{
signanl(SIGUSR1,sig_usr);
...
}
当在执行SIGUSR1信号句柄时,SIGUSR1信号在执行设置SIGUSR1信号句柄前出现,将导致进程的终止。因为在执行信号句柄时系统将重置该信号的动作为默认动作。
signal是不可靠的,应该使用可靠的sigaction设置信号的动作。
使用signal( )设置信号的动作:
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
static void sig_usr(int sig) /*信号句柄*/
{
fprintf(stdout,"voer!\n");
return;
}
int main()
{
if(signal(SIGUSR1,sig_usr) == SIG_ERR) /*设置信号动作*/
{
fprintf(stderr,"failg!\n");
exit(1);
}
while(1) /*挂起直到有SIGUSR1信号出现*/
{
pause();
}
return 0;
}
sigaction( )函数
#include <signal.h>
int sigaction(int signum,const strcut sigaction *act,strcut sigaction *oact);
signum:制定的信号。
act:设置信号的动作。
oact:保存前一信号的动作。
act为NULL,oact不为NULL查询当前的信号动作。
act不为NULL,oact为NULL设置信号动作。
act,oact不为NULL,设置信号动作,并保存前一信号动作。
调用成功返回0,不成功返回-1,且不安装新动作;
结构体sigaction定义:
struct sigaction
{
void (*sa_handler) ( );
void (*sa_sigaction) (int,siginfo_t*,siginfo*);
sigset_t sa_mask;
int sa_flags;
};
第一个成员变量:指定与信号相连的动作,指定一个信号句柄。
第二个成员变量:指定与信号相连的动作,指定一个信号句柄。
第三个成员变量:sa_mask要屏蔽的信号集合。
第四个成员变量:sa_flags 标志变量。
#include <signal.h>
int sigempty(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); /*查看信号机中的成员*/
调用失败返回-1,成功返回0;
设置屏蔽信号:
#include <signal.h>
int sigprocmask (int how,const sigset_t *set,sigset_t *oset); /*改变调用进程的状态*/
how:如何改变信号的屏蔽。
SIG_BLOCK:阻塞set所指信号集的信号集,即将它们加入到当前的信号屏蔽中。
SIG_UNBLOCK:放开set所指的信号集,即将它们从当前的信号屏蔽中删除。
SIG_SETMASK:用set所指的信号集作为进程新的信号集,抛弃原先的信号屏蔽值。
set为NULL,oset不为NULL只查看,不改变。
set不为NULL,oset为NULL只改变。
set和oset都部位NULL,改变屏蔽信号,保存前一信号到oset。
sigpromask( ) 不能阻塞SIGKILL和SIGSTOP信号。
检查挂起信号:
#include <signal.h>
int sigpending (sigset_t *set); /*检查挂起信号*/
检查挂起信号:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
int main()
{
sigset_t base,old,work; /*定义信号集*/
int sig;
sigemptyset(&base); /*清空将要设置的信号集*/
sigaddset(&base,SIGQUIT); /*添加SIGQUIT信号*/
sigaddset(&base,SIGSTOP); /*添加SIGSTOP信号*/
if(sigprocmask(SIG_BLOCK,&base,&old) < 0) /*屏蔽base信号集的信号*/
fprintf(stderr,"mask faile!\n");
fprintf(stdout,"Plase weite!\n");
sleep(10); /*睡眠10秒*/
sigpending(&work); /*查看挂起的信号集*/
for(sig = 1; sig < NSIG; sig++) /*遍历挂起的信号集*/
if(sigismember(&work,sig))
psignal(sig,"there is a pending signel!\n");
if(sigprocmask(SIG_BLOCK,&old,NULL) < 0) /*恢复旧的屏蔽信号*/
exit(1);
printf("over!\n");
exit(0); /*退出*/
}
1.5 等待信号
include <unistd.h>
voud pause(void) /*挂起调用进程直到有信号到达*/
只有这个信号执行句柄函数并且句柄函数返回时,pause()系统调用才会返回。
paus()隐藏这严重的时间窗口错误,导致程序的神秘挂起。
<span style="font-size:14px;">#include <signal.h>
int sigsuspend(cost sigset_t *sigmask); /*挂起sigmask信号集,知道有不属于sigmask信号集的信号到来*/</span>
使用sigmask的信号集暂时代替进程的信号屏蔽,挂起调用进程直到有不属于sigmask的信号到来。
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
volatile int falg = 0;
static void sig_usr(int signo) /*信号SIGUSR1和信号SIGUSR2的语句柄*/
{
psignal(signo,"received!\n");
}
static void sig_intr(int signo) /*信号SIGINT的语句柄,置位标识变量*/
{
psignal(signo,"received!\n");
falg = 1;
}
void wait_for_signal(int sig,volatile int *f) /**/
{
static sigset_t mask,oldMask;
sigemptyset(&mask); /*清空信号集*/
sigaddset(&mask,sig); /*添加信号集*/
if(sigprocmask(SIG_BLOCK,&mask,&oldMask) < 0) /*暂时屏蔽mask信号的集合*/
{
fprintf(stderr,"SIG_BOLK error!\n");
exit(1);
}
sigdelset(&oldMask,SIGUSR1); /*从前一信号集合中删除SIGUSR1*/
sigdelset(&oldMask,SIGUSR2); /*从前一信号集合中删除SIGUSR2*/
while(!*f) /*循环等待SIGINT信号的到来*/
{
printf("Open!\n");
sigsuspend(&oldMask);
printf("Close\n");
}
*f = 0;
if(sigprocmask(sig,&oldMask,NULL) < 0) /*恢复前一屏蔽信号集*/
fprintf(stderr,"fail\n");
}
int main()
{
pid_t pid;
static sigset_t mask,oldmask;
signal(SIGUSR1,sig_usr); /*为SIGUSR1信号添加语句柄*/
signal(SIGUSR2,sig_usr); /*为SIGUSR2信号添加语句柄*/
signal(SIGINT,sig_intr); /*为SIGINT信号添加语句柄*/
sigemptyset(&mask); /*清空mask信号集*/
sigaddset(&mask,SIGUSR1); /*添加SIGUSR1信号集合*/
sigaddset(&mask,SIGUSR2); /*添加SIGUSR2信号集合*/
if(sigprocmask(SIG_BLOCK,&mask,&oldmask) < 0) /*暂时屏蔽mask信号集合*/
{
fprintf(stderr,"SIG_BLOCK\n");
exit(1);
}
if((pid = fork()) == 0) /*创造子进程*/
{
kill(getppid(),SIGUSR1); /*给父进程发送SIGUSR1信号*/
kill(getppid(),SIGUSR2); /*给父进程发送SIGUSR2信号*/
printf("child OK\n");
while(1); /*循环等待*/
}
else
{
wait_for_signal(SIGINT,&falg);
printf("Now,I can do my work!\n");
kill(pid,SIGTERM); /*杀死子进程*/
}
exit(0);
}
1.6 原子数据
对它的访问操作不会在半途中断的数据,任何访问它的操作要么没有完成,要么已经完成,不存在中间状态。