什么是信号:在计算机科学中,信号(英语:Signals
)是Unix
、类Unix
以及其他POSIX
兼容的操作系统中进程间通讯的一种有限制的方式。它是一种异步的通知机制,用来提醒进程一个事件已经发生。当一个信号发送给一个进程,操作系统中断了进程正常的控制流程,此时,任何非原子操作都将被中断。如果进程定义了信号的处理函数,那么它将被执行,否则就执行默认的处理函数。
在头文件
中,信号名都被定义为正整数常量。不存在值为0的有特殊的应用
产生信号的条件:
kill()
系统调用会在权限允许的情况下向进程发送特定的信号,类似地,kill
命令允许用户向进程发送信号。raise(3)
库函数可以将特定信号发送给当前进程。SIGFPE
和SIGSEGV
,默认都会导致进程终止和核心转储).SIGPIPE
信号,默认情况下会使进程关闭。信号是异步处理的经典实例。产生的信号事件对于进程而言是随机出现的,当出现该信号时,可以告诉内核按照3种方式之一进行处理。
signal
signal函数
#include
void (*signal(int signo , void(*func)(int)))(int));
//返回值:若成功,返回以前的信号处理配置;若出错,返回SIG_ERR
以下是一个简单的信号处理函数,它捕获两个用户定义的信号并打印信号编号。
#include
#include
#include
#include
#include
static void sig_usr(int);
int main()
{
if (signal(SIGUSR1,sig_usr) == SIG_ERR)
{
printf("can't catch SIGNUSR1\n");
}
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
{
printf("can't catch SIGUSR2\n");
}
for (; ;)
pause();
}
static void sig_usr(int signo)
{
if (signo == SIGUSR1)
printf("received SIGUSR1\n");
else if(signo == SIGUSR2)
printf("received SIGUSR2\n");
else
{
printf("reveived signal %d\n", signo);
}
}
输出:&
为在后台启动进程
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ./SignalProcess &
[1] 829
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ kill -USR1 829
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ received SIGUSR1
kill -USR2 829
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ received SIGUSR2
kill 829
[1]+ Terminated ./SignalProcess
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$
早期的UNIX版本中,信号是不可靠的
当捕捉到信号时,需要对其进行处理。进程正在执行的正常指令就会被信号处理程序临时中断,当信号处理程序返回时,会继续执行进程中的指令。此时可能破坏原来进程。
若一个程序或子程序可以“安全的被并行执行(Parallel computing
)”,则称其为可重入(reentrant
或re-entrant
)的。即当该子程序正在运行时,可以再次进入并执行它(并行执行时,个别的执行结果,都符合设计时的预期)。可重入概念是在单线程操作系统的时代提出的。一个子程序的重入,可能由于自身原因,如执行了jmp或者call,类似于子程序的递归调用;或者由于硬件中断,UNIX系统的signal的处理,即子程序被中断处理程序或者signal处理程序调用。重入的子程序,按照后进先出线性序依次执行。
若一个函数是可重入的,则该函数:
- 不能含有静态(全局)非常量数据。
- 不能返回静态(全局)非常量数据的地址。
- 只能处理由调用者提供的数据。
- 不能依赖于单实例模式资源的锁。
- 不能调用(call)不可重入的函数(有呼叫(call)到的函数需满足前述条件)。
多“用户/对象/进程优先级”以及多进程,一般会使得对可重入代码的控制变得复杂。同时,IO代码通常不是可重入的,因为他们依赖于像磁盘这样共享的、单独的(类似编程中的静态(Static)、全域(Global))资源。
如果函数是可重入的,说明该函数是异步信号安全的(async-signal safe)
以下的例子中嗲用一个非可重入函数getpwnam
#include
#include
#include
#include
#include
#include
static void my_alarm(int signo)
{
struct passwd* rootptr;
printf("in signal handle\n");
if ((rootptr = getpwnam("root")) == NULL )
{
printf("getpwnam(root) error\n");
}
alarm(1);
}
int main()
{
struct passwd* ptr;
signal(SIGALRM, my_alarm);
alarm(1);
for(;;)
{
if ((ptr = getpwnam("ubuntu")) == NULL)
printf("getpwnam error\n");
if (strcmp(ptr->pw_name, "ubuntu") != 0)
printf("return value corrupted!, pw_name = %s\n", ptr->pw_name);
}
exit(0);
}
SIGCLD
语义参考:http://blog.csdn.net/caianye/article/details/6453774
kill
和raise
信号集是一个能表示多个信号的数据类型。如果定义sigset_t set;
,那么set即为一个信号集合。
#include
int sigemptyset(sigset_t *set); //初始化:清空
int sigfillset(sigset_t *set); //初始化:填满
int sigaddset(sigset_t *set, int signo); //增
int sigdelset(sigset_t *set, int signo); //删
//4个函数返回值:若成功,返回0;若出错,返回-1
int sigismember(const sigset_t *set, int signo);//成员
//返回值:若真,返回1;若假,返回0
以下程序测试信号集:
/*
* 测试信号集
* */
#include
#include
#include
#include
#include
int main()
{
sigset_t sigset;
sigfillset(&sigset); //填充所用信号
if (sigismember(&sigset, SIGINT))
printf("SIGINT exist int sigal set!\n");
if (sigismember(&sigset,SIGTERM))
printf("SIGTERM exits in signal_set!\n");
if (sigismember(&sigset,SIGABRT))
printf("SIGABRT exist in signal_set!\n");
if (sigdelset(&sigset,SIGINT) < 0)
perror("del error\n");
else
printf("SIGINT has been removed!\n");
if (sigismember(&sigset,SIGINT))
printf("SIGINT exist in signal_set!\n");
else
printf("SIGINT not exist in signal_set!\n");
exit(0);
}
输出:
SIGINT exist int sigal set!
SIGTERM exits in signal_set!
SIGABRT exist in signal_set!
SIGINT has been removed!
SIGINT not exist in signal_set!
sigprocmask
函数sigprocmask
可以检测或更该或同时进行更该进程信号屏蔽字。
#include
int sigprocmask(int how, const siget_t *restrict set,siget_t *restrict oset);
//返回值:若成功,返回0;若出错,返回-1
SIG_BLOCK
当前信号屏蔽字并上set指向的信号屏蔽字SIG_UNBLOCK
当前信号屏蔽字去掉setSIG_SETMASK
set替换当前信号屏蔽字sigpending
sigpending
函数返回在送往进程的时候被阻塞挂起的信号集合。这个信号集合通过参数set返回.
#include
int sigpending(sigset_t *set);
//返回值:若成功,返回0;若出错,返回-1
#include
#include
#include
#include
//捕获函数
void sig_quit(int signo)
{
printf("caught SIGQUIT\n");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
printf("Can't reset SIGQUIT\n");
}
int main()
{
sigset_t newmask, oldmask, pendmask;
//捕获SIGQUIT信号
if (signal(SIGQUIT, sig_quit) == SIG_ERR)
printf("Can't catch SIGQUIT.\n");
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
printf("SIG_BLOCK error\n");
sleep(5);
//信号捕获后被阻塞,因此会被sigpending函数返回
if (sigpending(&pendmask) < 0)
printf("sigpending error\n");
if (sigismember(&pendmask, SIGQUIT))
printf("\nSIQGUIT pending\n");
//将信号屏蔽字设置为oldmask
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
printf("SIG_SETMASK ERROR\n");
printf("SIGQUIT unblocked \n");
sleep(5);
exit(0);
}
程序输出:
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ./a.out
^\^\^\^\^\
SIQGUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\Quit
函数sigaction
的功能是检查或修改指定信号相关联的处理动作,取代了早期的signal
函数.
#include
int sigaction(int signo,
const struct sigaction *restrict act ,
struct sigaction *restrict oact);
//返回值:若成功,返回0;若出错,返回-1
[以下参考:http://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html]
sigaction结构体如下:
struct sigaction{
void (*sa_handler)(int);/* addr of signal handler,*/
/*or SIG_IGN, OR SIG_DFL*/
sigset_t sa_mask; /*additional signals to block*/
int sa_flags; /*signal options, Figure 10.16*/
/*alternate handler*/
void (sa_sigaction)(int, siginfo_t *, void *);
}
sa_handler
是一个函数指针,其含义与 signal 函数中的信号处理函数类似。sa_sigaction
是另一个信号处理函数,它有三个参数,可以获得关于信号的更详细的信息。当 sa_flags 成员的值包含了 SA_SIGINFO 标志时,系统将使用 sa_sigaction 函数作为信号处理函数,否则使用 sa_handler 作为信号处理函数。注意:在某些系统中,成员 sa_handler 与 sa_sigaction 被放在联合体中,因此使用时不要同时设置。sa_mask
:成员用来指定在信号处理函数执行期间需要被屏蔽的信号,特别是当某个信号被处理时,它自身会被自动放入进程的信号掩码,因此在信号处理函数执行期间这个信号不会再度发生。sa_flags
:成员用于指定信号处理的行为,它可以是以下值的“按位或”组合。 使用的例子:
#include
#include
#include
#include
#include
static void sig_usr(int signum)
{
if (signum == SIGUSR1)
printf("SIGUSR1 received.\n");
else if (signum == SIGUSR2)
printf("SIGUSR2 received.\n");
else
printf("signal %d received.\n", signum);
}
int main(void)
{
char buf[512];
int n;
struct sigaction sa_usr;
sa_usr.sa_flags = 0;
sa_usr.sa_handler = sig_usr;
sigaction(SIGUSR1, &sa_usr, NULL);
sigaction(SIGUSR2, &sa_usr, NULL);
printf("My PID is %d\n", getpid());
while(1)
{
if ((n = read(STDIN_FILENO, buf, 511)) == -1)
{
if (errno == EINTR)
printf("read is interrupted by sianal\n");
else
{
buf[n] = '\0';
printf("%d bytes read:%s\n", n, buf);
}
}
}
exit(0);
}
My PID is 23252
kill -USR1 23252
,程序显示如下:SIGUSR1 received.
read is interrupted by sianal
siginfo_t
结构包含了信号产生原因的有关信息,该结构如下struct siginfo {
int si_signo; /* signal number */
int si_errno; /* if nonzero, errno value from */
int si_code; /* additional info (depends on signal) */
pid_t si_pid; /* sending process ID */
uid_t si_uid; /* sending process real user ID */
void *si_addr; /* address that caused the fault */
int si_status; /* exit value or signal number */
long si_band; /* band number for SIGPOLL */
/* possibly other fields also */
};
以下是signal函数的实现
Sigfunc* signal(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;
}
必须用sigemptyset函数初始化act结构的sa_mask成员。不能保证:act.sa_mask = 0;会做同样的事情。
对除SIGALRM以外的所有信号,我们都有尝试设置SA_RESTART标志,于是被这些信号中断的系统调用都能自动重启动。不希望重启动由SIGALRM信号中断的系统调用的原因是:我们希望对I/O操作可以设置时间限制。
sigsetjmp
和siglongjmp
longjmp
函数以返回到程序的主循环中。longjmp
,当捕捉一个信号时,进入信号捕捉函数,此时当前信号被自动加到进程的信号屏蔽字中。这样后来产生的这种信号中断不能被捕获。sigsetjmp
和siglongjmp
。如果需要在信号处理程序中进行非局部转移,可以使用这两个函数.#include
int sigsetjmp(sigjmp_buf env, int savemask);
//返回值:若直接调用,返回0;若从siglongjmp调用返回,则返回非0
void siglongjmp(sigjmp_buf env, int val);
savemask
非0,则sigsetjm
p在env中保存进程的当前信号屏蔽字。siglongjmp
时,如果带非0savemask
的sigsetjmp
调用已经保存了env,则siglongjmp
从其中恢复保存的信号屏蔽字。#include
#include
#include
#include
#include
#include
#include
#include
void pr_mask(const char* str)
{
sigset_t sigset;
int errno_save;
errno_save = errno; //保存的errno
if (sigprocmask(0, NULL, &sigset) < 0)
{
printf("sigprocmask error!\n");
exit(1);
}
else
{
printf("%s", str);
if (sigismember(&sigset, SIGINT))
printf("SIGINT");
if (sigismember(&sigset, SIGQUIT))
printf(" SIGQUIT");
if (sigismember(&sigset, SIGUSR1))
printf(" SIGUSR1");
if (sigismember(&sigset, SIGUSR2))
printf(" SIGUSR2");
printf("\n");
}
}
static void sig_usr1(int);
static void sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjump;
int main(void)
{
if(signal(SIGUSR1,sig_usr1)==SIG_ERR)
printf("singnal SIGUSR1 error");
if(signal(SIGALRM,sig_alrm)==SIG_ERR)
printf("signal SIGALRM error");
pr_mask("staring main : \n");
if(sigsetjmp(jmpbuf,1))
{
pr_mask("ending main: \n");
exit(0);
}
canjump=1;
for(;;)
{
pause(); //终止保持信号接收
}
}
static void sig_usr1(int siigno)
{
time_t startime;
if(canjump==0)
{
return ;
}
pr_mask("staring sig_usr1 function\n");
alarm (3);
startime=time(NULL);
for(;;)
{
if(time(NULL)>startime +5)
break;
}
pr_mask("finishing the function sig_usr1\n");
canjump =0;
siglongjmp(jmpbuf,1);//返回主函数同前一例中的longjmp作用类似
}
static void sig_alrm(int signo )
{
pr_mask("int the function sig_alrm\n");
}
输出:
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ./a.out &
[1] 9387
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ staring main :
kill -USR1 9387
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ staring sig_usr1 function
SIGUSR1
int the function sig_alrm
SIGUSR1
finishing the function sig_usr1
SIGUSR1
ending main:
//按回车输出
[1]+ Done ./a.out
siglongjmp
就应该使用这种技术:仅在调用sigsetjmp
之后才将变量canjump设置为非0,在信号处理中检测此变量,仅为非0时才调用setlongjmp
.这样防止sigsetjmp
没有初始化jmpbuf就调用信号处理程序。sig_atomic_t
这种类型变量不会中断。sigsuspend
sigsuspend
的函数如下:
#include
int sigsuspend(const sigset_t *sigmask);
//返回值:-1,并将errno设置为EINTR
sigmask
指向的值。sigsuspend
返回,并且该进程的信号屏蔽字设置为调用sigsuspend
之前的值。一个保护代码临界区的例子:
#include
#include
#include
#include
#include
#include
void pr_mask(const char* str)
{
sigset_t sigset;
int errno_save;
errno_save = errno; //保存的errno
if (sigprocmask(0, NULL, &sigset) < 0)
{
printf("sigprocmask error!\n");
exit(1);
}
else
{
printf("%s", str);
if (sigismember(&sigset, SIGINT))
printf("SIGINT");
if (sigismember(&sigset, SIGQUIT))
printf(" SIGQUIT");
if (sigismember(&sigset, SIGUSR1))
printf(" SIGUSR1");
if (sigismember(&sigset, SIGUSR2))
printf(" SIGUSR2");
printf("\n");
}
}
static void sig_int(int signo)
{
pr_mask("\nin sig_int: ");
}
int main()
{
sigset_t newmask, oldmask, waitmask;
pr_mask("program start: ");
if (signal(SIGINT, sig_int) == SIG_ERR)
printf("signal(SIGINT) error.\n");
sigemptyset(&waitmask);
sigaddset(&waitmask, SIGUSR1);
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT);
//Block SIGINT and save current signal mask.
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
printf("SIG_BLOCK ERROR.\n");
pr_mask("in critical region: ");
//SIGINT信号被阻塞,将信号屏蔽恢复为原来的状态
if (sigsuspend(&waitmask) != -1)
printf("sigsuspend error.\n");
pr_mask("after return from sigsuspend:");
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
printf("SIG_SETMASK ERROR.\n");
pr_mask("program exit: ");
exit(0);
}
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ./a.out
program start:
in critical region: SIGINT
^C
in sig_int: SIGINT SIGUSR1
after return from sigsuspend:SIGINT
program exit:
sigsuspend
返回时,它将信号屏蔽字设置为调用它之前的值 sigsuspend
时,SIGUSR1
信号加到了进程信号屏蔽字中,所以当运行该信号时,我们得知该信号屏蔽字已经改变了。以下例子是sigsuspend
的另一种应用是等待一个信号处理程序设置一个全局变量。
#include
#include
#include
#include
volatile sig_atomic_t quitflag;
static void sig_int(int signo)
{
if (signo == SIGINT)
printf("\ninterrupt\n");
else if(signo == SIGQUIT)
quitflag = 1;
}
int main(void)
{
sigset_t newmask, oldmask, zeromask;
if(signal(SIGINT, sig_int) == SIG_ERR)
printf("signal (SIGINT) error!\n");
if (signal(SIGQUIT, sig_int) == SIG_ERR)
printf("signal(SIGIQUIT) error.\n");
sigemptyset(&zeromask);
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
while(quitflag == 0)
sigsuspend(&zeromask);
//SIGQUIT 信号被捕获
quitflag = 0;
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
printf("SIG_SETMASK error!\n");
exit(0);
}
程序输出:
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ./a.out
^C
interrupt
^C
interrupt
^\ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$
abort
abort
函数的功能是使程序异常终止
#include
void abort(void);
//此函数不返回值
SIGABRT
信号发送给调用进程(进程不应该忽略此信号)abort的实现
#include
#include
#include
#include
void abort()
{
sigset_t mask;
struct sigaction action;
sigaction(SIGABRT, NULL, &action);
if (action.sa_handler == SIG_IGN)
{
action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &action, NULL);
}
if (action.sa_handler == SIG_DEL)
fflush(NULL);
sigfillset(&mask);
sigdelset(&mask, SIGABRT);
sigprocmask(SIG_SETMASK, &mask, NULL);
kill(getpid(), SIGABRT);
fflush(NULL);
action.sa_handler = SIG_DEL;
sigaction(SIGABRT, &mask, NULL);
sigprocmask(SIG_SETMASK, &mask, NULL);
kill(getpid(), SIGABRT);
exit(1);
}
system
参考:http://www.cnblogs.com/mickole/p/3187974.html
system()函数调用/bin/sh -c command
执行特定的命令,阻塞当前进程直到command命令执行完毕.
函数原型:int system(const char *command);
函数返回值:如果无法启动shell运行命令,system将返回127;出现不能执行system调用的其他错误时返回-1。如果system能够顺利执行,返回那个命令的退出码。
system函数执行时,会调用fork、execve、waitpid等函数。
Linxu下的system函数源码:
int system(const char * cmdstring)
{
pid_t pid;
int status;
if(cmdstring == NULL){
return (1);
}
if((pid = fork())<0){
status = -1;
}
else if(pid == 0){
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
_exit(127); //子进程正常执行则不会执行此语句
}
else{
while(waitpid(pid, &status, 0) < 0){
if(errno != EINTER){
status = -1;
break;
}
}
}
return status;
}
system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命>令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。
返回值
=-1
:出现错误 =0
:调用成功但是没有出现子进程 >0
:成功退出的子进程的id 阶段1:创建子进程等准备工作。如果失败,返回-1。
阶段2:调用/bin/sh拉起shell脚本,如果拉起失败或者shell未正常执行结束(参见备注1),原因值被写入到status的低8~15比特位中。system的man中只说明了会写了127这个值,但实测发现还会写126等值。
阶段3:如果shell脚本正常执行结束,将shell返回值填到status的低8~15比特位中。
备注1:
只要能够调用到/bin/sh,并且执行shell过程中没有被其他信号异常中断,都算正常结束。
比如:不管shell脚本中返回什么原因值,是0还是非0,都算正常执行结束。即使shell脚本不存在或没有执行权限,也都算正常执行结束。
如果shell脚本执行过程中被强制kill掉等情况则算异常结束。
如何判断阶段2中,shell脚本子进程是否正常执行结束呢?系统提供了宏:WIFEXITED(status)。如果WIFEXITED(status)为真,则说明正常结束。
如何取得阶段3中的shell返回值?你可以直接通过右移8bit来实现,但安全的做法是使用系统提供的宏:WEXITSTATUS(status)。
由于我们一般在shell脚本中会通过返回值判断本脚本是否正常执行,如果成功返回0,失败返回正数。
所以综上,判断一个system函数调用shell脚本是否正常结束的方法应该是如下3个条件同时成立:
(1)-1 != status
(2)WIFEXITED(status)为真
(3)0 == WEXITSTATUS(status)
注意:
根据以上分析,当shell脚本不存在、没有执行权限等场景下时,以上前2个条件仍会成立,此时WEXITSTATUS(status)为127,126等数值。
所以,我们在shell脚本中不能将127,126等数值定义为返回值,否则无法区分中是shell的返回值,还是调用shell脚本异常的原因值。shell脚本中的返回值最好多1开始递增。
#include
#include
#include
#define EXIT_ERR(m) \
{\
perror(m);\
exit(EXIT_FAILURE);\
}\
while (0);\
int main()
{
int status;
status = system("ls -l|wc -l");
if (status == -1)
{
EXIT_ERR("system error");
}
else
{
if (WIFEXITED(status))
{
if (WEXITSTATUS(status)==0)
printf("run command successful\n");
else
printf("run command fail and exit code is %d\n", WEXITSTATUS(status));
}
else
{
printf("exit status = %d\n", WEXITSTATUS(status));
}
}
return 0;
}
16
run command successful
sleep
, nanosleep
和clock_nanosleep
sleep函数的原型为:
#include
unsigned int sleep(unsigned int seconds);
//返回值:0或为休眠完的秒数
此函数使调用进程挂起直到满足下面两个条件之一。
nanosleep函数与sleep函数类似,但提供了纳秒级的精度
#include
int nanosleep(const struct timespec *reqtp, struct timespec *remtp);
//返回值:若休眠到要求的时间,返回0;若出错,返回-1
reqpt参数用秒和纳秒指定需要休眠的时间长度。如果某个信号中断了休眠间隔,程序并没有终止,remtp参数指向的timespec结构就会被设置为未休眠完的时间长度。如果对为休眠完的时间并不感兴趣,可以把该参数置为NULL;
随着多个系统时钟的引入,需要使用相对于特定时钟的延迟时间来挂起调用线程。clock_nanosleep
函数提供了这种功能
#include
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *reqtp,
struct timespec *remtp);
//返回值:若休眠要求的时间,返回0;如出错,返回错误号
sigqueue
参考:http://www.cnblogs.com/mickole/p/3191804.html
在POSIX.1的实时扩展中,一些系统开始对信号排队的支持。
使用排队信号必须做以下几个操作
函数原型:
#include
#include
int sigqueue(pid_t pid, int sig, const union sigval val)
调用成功返回 0;否则,返回 -1。
typedef union sigval {
int sival_int;
void *sival_ptr;
}sigval_t;
例子:给自己发数据
//use sigqueue()
#include
#include
#include
#include
void sighandler(int signo, siginfo_t *info, void *ctx)
{
//以下两种方式都能获得sigqueue发送的数据
printf("receive the data by info->si_int: %d\n", info->si_int);
printf("receive the data by info->si_value.sival_int:%d\n", info->si_value.sival_int);
}
int main()
{
struct sigaction act;
act.sa_sigaction = sighandler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO; //信号传递开关
if (sigaction(SIGINT, &act, NULL) == -1)
{
perror("sigaction error!");
exit(1);
}
sleep(2);
union sigval mysigval;
mysigval.sival_int = 1000;
if (sigqueue(getpid(), SIGINT, mysigval) == -1)
{
perror("sigqueue error!");
exit(1);
}
return 0;
}
运行结果:
receive the data by info->si_int: 1000
receive the data by info->si_value.sival_int:1000
例子:发送和接受信号
发送
//send datat use sigqueue()
#include
#include
#include
#include
int main(int argc, char** argv)
{
if (argc != 2)
{
fprintf(stderr, "usage:%s pid\n", argv[0]);
exit(1);
}
pid_t pid = atoi(argv[1]);
sleep(2);
union sigval mysigval;
mysigval.sival_int = 100;
printf("sending SIGINT signal to %d ......\n", pid);
if (sigqueue(pid, SIGINT, mysigval) == -1)
{
perror("sigqueue error!");
exit(1);
}
return 0;
}
接受:
//receive data use sigqueue()
#include
#include
#include
#include
void sighandler(int signo, siginfo_t *info, void *ctx)
{
//以下两种方式都能获得sigqueue发送的数据
printf("receive the data by info->si_int: %d\n", info->si_int);
printf("receive the data by info->si_value.sival_int:%d\n", info->si_value.sival_int);
}
int main()
{
struct sigaction act;
act.sa_sigaction = sighandler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO; //信号传递开关
if (sigaction(SIGINT, &act, NULL) == -1)
{
perror("sigaction error!");
exit(1);
}
for (;;)
{
printf("waiting a SIGINT signal...\n");
pause();
}
return 0;
}
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ps -ef|grep rev|grep -v /usr | grep -v grep|awk '{print $2}'
21045
ubuntu@VM-188-113-ubuntu:~/Code/apue/ch10Signal$ ./send 21045
sending SIGINT signal to 21045 ......
waiting a SIGINT signal...
receive the data by info->si_int: 100
receive the data by info->si_value.sival_int:100
waiting a SIGINT signal...
6个作业控制信号如下:
SIGCHLD
子进程已经停止或终止SIGCONT
如果进程停止,则使其继续运行SIGSTOP
停止信号SIGTSTP
交互式停止信号SIGTIN
后台进程组成员读控制终端SIGTOU
后天进程组成员写控制终端说明:
本节介绍如何在信号编号和信号名之间进行映射。
extern char* sys_siglist[]
数组下标是信号编号,数组中的元素是指向信号名字符串的指针psignal
函数可以打印与信号编号对应的字符串#include
void psignal(int signo, const char *msg);
#include
void psiginfo(const siginfo_t *info, const char *msg);
与psignal
类似
#include
char *strsignal(int signo);
//返回值:指向描述该信号的字符串的指针