APUE信号

pag233
信号都被定义为正整数。
不存在编号为0的信号。
不能捕捉SIGKILL和SIGSTOP信号。
信号的处理:
1,忽略信号
2,捕捉信号
3,执行系统默认动作(大多数信号默认动作时终止进程)

void (* signal (int signo, void(*fun)(int)))(int)
fun:
1、SIG_IGN  忽略信号
2、SIG_DFL 默认(通常时关闭)
3、调用函数地址
缺点:不改变信号的处理方式就不能确定信号的当前处理方式。

exec将原先设置为 要捕捉的信号都更改为他们的 默认动作其他信号的状态则 不变(对于一个进程原先要捕捉的信号,当其执行一个新程序后,就自然不能捕捉他了,因为信号捕捉函数的地址很可能在所执行的新程序文件中已无意义)

pag244
当捕捉到某个信号时被中断的是内核中执行的系统调用。
不可重入函数特征:
1,使用静态数据结构
2,调用malloc或free
3,标准IO函数

信号的阻塞就是让系统暂时保留信号留待以后发送

sigaction可设置SA_NOCLDWAIT标志以避免子进程僵死(这样就不用执行信号处理函数再waitpid了)

pag250
信号未决
在信号产生和递送之间的时间间隔内,称信号是未决的。

若同一种信号多次发生,通常并不将他们排队,所以如果在某种信号被阻塞时他发生了五次,那么对这种信号解除阻塞后,其信号处理函数通常只会被调用一次。

当执行信号处理程序时,若新信号(相同信号)抵达,signal默认将该信号加入进程的信号队列中,直至信号处理程序执行结束。(多次抵达只取第一次)(现在在ubuntu上实测signal是这样的,APUE上面是不自动阻塞,执行信号默认操作)

发送信号:
int kill(pid_t pid, int signo)
int raise(int signo)  //给自身发送信号
调用kill为调用进程产生信号,而且此信号是不被阻塞的,那么在kill返回之前,就会将signo或者某个其他未决的非阻塞信号传送至该进程。

unsigned int alarm( unsigned intseconds ) // 每个进程只能有一个闹钟时钟
int pause( void )//使调用进程挂起直至捕捉到一个信号并从信号处理程序返回

pag256
所有应用程序在使用信号集前,要对该信号集调用sigemptyset或sigfillset一次.(因c编译器把未赋初值的外部和静态变量都初始化为0)
信号集:
int sigemptyset( sigset_t *set)  //清除信号集所有信号
int sigfillset( sigset_t *set)          //设置所有信号
int sigaddset( sigset_t *set, intsigno ) //向信号集中添加信号(要阻塞的)
int sigdelset( sigset_t *set, intsigno )    //从信号集中移除信号
int sigismember( const sigset_t *set,int signo )  //测试信号是否在信号集中

int sigprocmask( int how, constsigset_t *restrict set, sigset_t *restrict oset)//oset返回当前屏蔽字(处理单线程)
how:
1、SIG_BLOCK 将当前信号屏蔽字和set指向信号集的相并
2、SIG_UNBLOCK 将当前信号屏蔽字和set指向信号集补集的相交
3、SIG_SETMASK 进程新的信号屏蔽字被set指向的信号集代替
sigprocmask仅为单线程的进程定义。pthread_sigmask为多线程进程定义

int sigpending ( sigset_t *set )
返回信号集,其中各个信号对于调用进程时阻塞的而不能递送,因而也一定是当前未决的。

int sigaction( int signo, const structsigaction *restrict act, struct sigaction *restrict oact )
oact 非空时返回该信号的上一次动作(包括信号屏蔽字)
struct sigaction
{
      void(*sa_handler)(int);    //信号捕捉函数地址
      sigset_tsa_mask;              //信号集。调用信号捕捉函数之前,此信号集加到进程信号集中, 捕捉函数返回时恢复为原值(这里的捕捉信号函数之前这个说法要注意,下说明)
      int                  sa_flags;    //指定对信号处理的各个选项
      void(*sa_sigaction)(int, siginfo_t, void*);      //替代的信号处理程序(2个处理函数只能选其一)
}
在信号处理程序被调用时,操作系统建立的 新信号屏蔽字包括正在被递送的信号,因此保证了在处理一个给定信号时,如果这种信号再次发生,那么他会被阻塞到对前一个信号的处理结束为止。
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

sigset_t	sigmask;
struct sigaction	act, oact;
static void 
sig_handler(void *signo)
{
	if (sigprocmask(0, NULL, &sigmask) < 0)
		fprintf(stderr, "sigprocmask error\n");
	if (sigismember(&sigmask, SIGALRM))
		printf("\nSIGALRM have been masked in handle function\n");
	if (sigismember(&sigmask, SIGINT))
		printf("SIGINT has been masked in handle function\n");
	printf("handle signal\n");
}
int
main(int argc, char *argv[])
{

	sigemptyset(&sigmask);
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask, SIGALRM);
	act.sa_handler = sig_handler;
	act.sa_flags = 0;
	if (sigaction(SIGINT, &act, &oact) < 0)
		fprintf(stderr, "sigaction error\n");

	if (sigismember(&oact.sa_mask, SIGALRM))
		printf("SIGALRM has already been masked\n");

	if (sigprocmask(0, NULL, &sigmask) < 0)
		fprintf(stderr, "sigprocmask error\n");
	if (sigismember(&sigmask, SIGALRM))
		printf("SIGALRM has been masked in main process\n");
	if (sigismember(&sigmask, SIGINT))
		printf("SIGINT has been masked in main process\n");

	pause();
	printf("done\n");

	exit(0);
}

程序输出:
^C
SIGALRM have been masked in handle function    //1
SIGINT has been masked in handle function           //2
done
1:(说明sigaction在处理信号时才将sa_mask信号集添加进进程信号屏蔽字,书上的在“调用捕捉函数之前加入”这句让我理解错误了,以为调用sigaction以后就加入信号屏蔽字,捕捉信号,并从信号处理函数返回以前都是阻塞sa_mask中的信号的,实际上只有在信号处理函数中才阻塞sa_mask中的信号,和2中的差不多,只不过一个是系统自动添加,一个是人为设定信号集通过sigaction添加到进程信号屏蔽字),可能书中“在调用该信号的捕捉函数之前”的意思是:已经捕捉到信号了,但是还没且将要执行信号处理函数,这样就和输出结果一致了。。
2:(说明系统在处理信号时会将正在处理的信号加入进程信号屏蔽字)


int sigsuspend(const sigset_t *sigmask)
原子操作:先恢复成sigmask指定的信号屏蔽字,再使进程休眠
在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并将信号屏蔽字设置为调用sigsuspend之前的值( 设定----捕捉----处理----恢复

unsigned int sleep(unsigned intseconds)
挂起恢复条件:
1、过了seconds
2、调用进程捕捉到信号并从信号处理程序返回

void psignal(int signo, const char*msg);//;类似perror
char * strsignal(intsigno);//类似strerror

int sig2str(int signo, char*str);//将信号编号翻译成字符串
int str2sig(const char *str, int*signop);//将给出的名字翻译为字符串

例子:
#include                                                                                                                       
#include
#include

static void
sig_print(int signo)
{
      printf("signal is %d\n", getpid());
}
int
main(int argc, char **argv)
{
      pid_t            pid;

      signal(SIGINT, sig_print);
      if ((pid =fork()) == 0) {
              sleep(5);
              exit(0);
      }   
      sleep(5);
      exit(0);
}

输出:
signal is 3489
signal is 3490

SIGINT信号传送给前台进程组里的所有进程

你可能感兴趣的:(APUE信号)