signal()函数
转自:http://blog.csdn.net/sddzycnqjn/article/details/7285760
1. 信号概念
信号是进程在运行过程中,由自身产生或由进程外部发过来的消息(事件)。信号是硬件中断的软件模拟(软中断)。每个信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件中定义,也可以通过在shell下键入kill –l查看信号列表,或者键入man 7 signal查看更详细的说明。
信号的生成来自内核,让内核生成信号的请求来自3个地方:
l 用户:用户能够通过输入CTRL+c、Ctrl+\,或者是终端驱动程序分配给信号控制字符的其他任何键来请求内核产生信号;
l 内核:当进程执行出错时,内核会给进程发送一个信号,例如非法段存取(内存访问违规)、浮点数溢出等;
l 进程:一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。
由进程的某个操作产生的信号称为同步信号(synchronous signals),例如除0;由象用户击键这样的进程外部事件产生的信号叫做异步信号。(asynchronous signals)。
进程接收到信号以后,可以有如下3种选择进行处理:
l 接收默认处理:接收默认处理的进程通常会导致进程本身消亡。例如连接到终端的进程,用户按下CTRL+c,将导致内核向进程发送一个SIGINT的信号,进程如果不对该信号做特殊的处理,系统将采用默认的方式处理该信号,即终止进程的执行;
l 忽略信号:进程可以通过代码,显示地忽略某个信号的处理,例如:signal(SIGINT,SIGDEF);但是某些信号是不能被忽略的,
l 捕捉信号并处理:进程可以事先注册信号处理函数,当接收到信号时,由信号处理函数自动捕捉并且处理信号。
有两个信号既不能被忽略也不能被捕捉,它们是SIGKILL和SIGSTOP。即进程接收到这两个信号后,只能接受系统的默认处理,即终止线程。
2. signal信号处理机制
可以用函数signal注册一个信号捕捉函数。原型为:
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal 的第1个参数signum表示要捕捉的信号,第2个参数是个函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DEF(表示交由系统缺省处理,相当于白注册了)或SIG_IGN(表示忽略掉该信号而不做任何处理)。signal如果调用成功,返回以前该信号的处理函数的地址,否则返回 SIG_ERR。
sighandler_t是信号捕捉函数,由signal函数注册,注册以后,在整个进程运行过程中均有效,并且对不同的信号可以注册同一个信号捕捉函数。该函数只有一个参数,表示信号值。
示例:
1、 捕捉终端CTRL+c产生的SIGINT信号:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
void SignHandler(int iSignNo)
{
printf("Capture sign no:%d/n",iSignNo);
}
int main()
{
signal(SIGINT,SignHandler);
while(true)
sleep(1);
return 0;
}
该程序运行起来以后,通过按 CTRL+c将不再终止程序的运行。应为CTRL+c产生的SIGINT信号已经由进程中注册的SignHandler函数捕捉了。该程序可以通过 Ctrl+/终止,因为组合键Ctrl+/能够产生SIGQUIT信号,而该信号的捕捉函数尚未在程序中注册。
2、 忽略掉终端CTRL+c产生的SIGINT信号:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
signal(SIGINT,SIG_IGN);
while(true)
sleep(1);
return 0;
}
该程序运行起来以后,将CTRL+C产生的SIGINT信号忽略掉了,所以CTRL+C将不再能是该进程终止,要终止该进程,可以向进程发送SIGQUIT信号,即组合键CTRL+/
3、 接受信号的默认处理,接受默认处理就相当于没有写信号处理程序:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
signal(SIGINT,DEF);
while(true)
sleep(1);
return 0;
}
3. sigaction信号处理机制
3.1. 信号处理情况分析
在signal处理机制下,还有许多特殊情况需要考虑:
1、 册一个信号处理函数,并且处理完毕一个信号之后,是否需要重新注册,才能够捕捉下一个信号;
2、 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个同类型的信号,这时该怎么处理;
3、 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个不同类型的信号,这时该怎么处理;
4、 如果程序阻塞在一个系统调用(如read(...))时,发生了一个信号,这时是让系统调用返回错误再接着进入信号处理函数,还是先跳转到信号处理函数,等信号处理完毕后,系统调用再返回。
示例:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iSeq=0;
void SignHandler(int iSignNo)
{
int iSeq=g_iSeq++;
printf("%d Enter SignHandler,signo:%d./n",iSeq,iSignNo);
sleep(3);
printf("%d Leave SignHandler,signo:%d/n",iSeq,iSignNo);
}
int main()
{
char szBuf[8];
int iRet;
signal(SIGINT,SignHandler);
signal(SIGQUIT,SignHandler);
do{
iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
if(iRet<0){
perror("read fail.");
break;
}
szBuf[iRet]=0;
printf("Get: %s",szBuf);
}while(strcmp(szBuf,"quit/n")!=0);
return 0;
}
程序运行时,针对于如下几种输入情况(要输入得快),看输出结果:
1、 CTRL+c] [CTRL+c] [CTRL+c]
2、 [CTRL+c] [CTRL+/]
3、 hello [CTRL+/] [Enter]
4、 [CTRL+/] hello [Enter]
5、 hel [CTRL+/] lo[Enter]
针对于上面各种情况,不同版本OS可能有不同的响应结果。
3.2. sigaction信号处理注册
如果要想用程序控制上述各种情况的响应结果,就必须采用新的信号捕获机制,即使用sigaction信号处理机制。
函数原型:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigaction也用于注册一个信号处理函数。
参数signum为需要捕捉的信号;
参数 act是一个结构体,里面包含信号处理函数地址、处理方式等信息。
参数oldact是一个传出参数,sigaction函数调用成功后,oldact里面包含以前对signum的处理方式的信息。
如果函数调用成功,将返回0,否则返回-1
结构体 struct sigaction(注意名称与函数sigaction相同)的原型为:
struct sigaction {
void (*sa_handler)(int); // 老类型的信号处理函数指针
void (*sa_sigaction)(int, siginfo_t *, void *);//新类型的信号处理函数指针
sigset_t sa_mask; // 将要被阻塞的信号集合
int sa_flags; // 信号处理方式掩码
void (*sa_restorer)(void); // 保留,不要使用。
}
该结构体的各字段含义及使用方式:
1、字段sa_handler是一个函数指针,用于指向原型为void handler(int)的信号处理函数地址, 即老类型 的信号处理函数;
2、字段sa_sigaction也是一个函数指针,用于指向原型为:
void handler(int iSignNum,siginfo_t *pSignInfo,void *pReserved);
的信号处理函数,即新类型的信号处理函数。
该函数的三个参数含义为:
iSignNum :传入的信号
pSignInfo :与该信号相关的一些信息,它是个结构体
pReserved :保留,现没用
3、字段sa_handler和sa_sigaction只应该有一个生效,如果想采用老的信号处理机制,就应该让sa_handler指向正确的信号处理函数;否则应该让sa_sigaction指向正确的信号处理函数,并且让字段 sa_flags包含SA_SIGINFO选项。
4、字段sa_mask是一个包含信号集合的结构体,该结构体内的信号表示在进行信号处理时,将要被阻塞的信号。针对sigset_t结构体,有一组专门的函数对它进行处理,它们是:
#include <signal.h>
int sigemptyset(sigset_t *set); // 清空信号集合set
int sigfillset(sigset_t *set); // 将所有信号填充进set中
int sigaddset(sigset_t *set, int signum); // 往set中添加信号signum
int sigdelset(sigset_t *set, int signum); // 从set中移除信号signum
int sigismember(const sigset_t *set, int signum); // 判断signnum是不是包含在set中
例如,如果打算在处理信号SIGINT时,只阻塞对SIGQUIT信号的处理,可以用如下种方法:
struct sigaction act;
sigemptyset(&act.sa_mask);
sigaddset(&act_sa_mask,SIGQUIT);
sigaction(SIGINT,&act,NULL);
5、 字段sa_flags是一组掩码的合成值,指示信号处理时所应该采取的一些行为,各掩码的含义为:
掩码 描述
SA_RESETHAND 处理完毕要捕捉的信号后,将自动撤消信号处理函数的注册,即必须再重新注册信号处理函数,才能继续处理接下来产生的信号。该选项不符合一般的信号处理流程,现已经被废弃。
SA_NODEFER 在处理信号时,如果又发生了其它的信号,则立即进入其它信号的处理,等其它信号处理完毕后,再继续处理当前的信号,即递规地处理。如果sa_flags包含了该掩码,则结构体sigaction的sa_mask将无效!
SA_RESTART 如果在发生信号时,程序正阻塞在某个系统调用,例如调用read()函数,则在处理完毕信号后,接着从阻塞的系统返回。该掩码符合普通的程序处理流程,所以一般来说,应该设置该掩码,否则信号处理完后,阻塞的系统调用将会返回失败!
SA_SIGINFO 指示结构体的信号处理函数指针是哪个有效,如果sa_flags包含该掩码,则sa_sigactiion指针有效,否则是sa_handler指针有效。
练习与验证:
针对于先前的5种输入情况,给下面代码再添加一些代码,使之能够进行如下各种形式的响应:
1 、[CTRL+c] [CTRL+c]时,第1个信号处理阻塞第2个信号处理;
2 、[CTRL+c] [CTRL+c]时,第1个信号处理时,允许递规地第2个信号处理;
3 、[CTRL+c] [CTRL+/]时,第1个信号阻塞第2个信号处理;
4 、read不要因为信号处理而返回失败结果。
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iSeq=0;
void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
{
int iSeq=g_iSeq++;
printf("%d Enter SignHandlerNew,signo:%d./n",iSeq,iSignNo);
sleep(3);
printf("%d Leave SignHandlerNew,signo:%d/n",iSeq,iSignNo);
}
int main()
{
char szBuf[8];
int iRet;
struct sigaction act;
act.sa_sigaction=SignHandlerNew;
act.sa_flags=SA_SIGINFO;
//
sigemptyset(&act.sa_mask);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
do{
iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
if(iRet<0){
perror("read fail.");
break;
}
szBuf[iRet]=0;
printf("Get: %s",szBuf);
}while(strcmp(szBuf,"quit/n")!=0);
return 0;
}
3.3. sigprocmask信号阻塞
函数sigaction中设置的被阻塞信号集合只是针对于要处理的信号,例如
struct sigaction act;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask,SIGQUIT);
sigaction(SIGINT,&act,NULL);
表示只有在处理信号SIGINT时,才阻塞信号SIGQUIT;
函数sigprocmask是全程阻塞,在sigprocmask中设置了阻塞集合后,被阻塞的信号将不能再被信号处理函数捕捉,直到重新设置阻塞信号集合。
原型为:
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数how的值为如下3者之一:
a :SIG_BLOCK ,将参数2的信号集合添加到进程原有的阻塞信号集合中
b :SIG_UNBLOCK ,从进程原有的阻塞信号集合移除参数2中包含的信号
c :SIG_SET,重新设置进程的阻塞信号集为参数2的信号集
参数set为阻塞信号集
参数oldset是传出参数,存放进程原有的信号集。
示例:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iSeq=0;
void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
{
int iSeq=g_iSeq++;
printf("%d Enter SignHandlerNew,signo:%d./n",iSeq,iSignNo);
sleep(3);
printf("%d Leave SignHandlerNew,signo:%d/n",iSeq,iSignNo);
}
int main()
{
char szBuf[8];
int iRet;
struct sigaction act;
act.sa_sigaction=SignHandlerNew;
act.sa_flags=SA_SIGINFO;
// 屏蔽掉SIGINT 信号,SigHandlerNew 将不能再捕捉SIGINT
sigset_t sigSet;
sigemptyset(&sigSet);
sigaddset(&sigSet,SIGINT);
sigprocmask(SIG_BLOCK,&sigSet,NULL);
//
sigemptyset(&act.sa_mask);
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
do{
iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
if(iRet<0){
perror("read fail.");
break;
}
szBuf[iRet]=0;
printf("Get: %s",szBuf);
}while(strcmp(szBuf,"quit/n")!=0);
return 0;
}
4. 用程序发送信号
4.1. kill信号发送函数
原型为:
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
参数pid为将要接受信号的进程的pid
参数sig为要发送的信号
如果成功,返回0,否则为-1。
示例,输入结束后,将通过发送信号SIGQUIT把自己杀掉:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
while(true){
if(getchar()==EOF)
kill(getpid(),SIGQUIT);
}
return 0;
}
4.2. sigqueue信号发送函数
sigqueue也可以发送信号,并且能传递附加的信息。
原型为:
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
参数pid为接收信号的进程;
参数sig为要发送的信号;
参数value为一整型与指针类型的联合体:
union sigval {
int sival_int;
void *sival_ptr;
};
由sigqueue函数发送的信号的第3个参数value的值,可以被进程的信号处理函数的第2个参数info->si_ptr接收到。
示例1,进程给自己发信号,并且带上附加信息:
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void SignHandlerNew(int signum,siginfo_t *info,void *myact)
{
char *pszInfo=(char *)(info->si_ptr);
printf("Get:%d info:%s/n",signum,pszInfo);
}
int main(int argc,char**argv)
{
struct sigaction act;
union sigval mysigval;
int sig;
char data[]="other info";
//
if(argc<2){
printf("usage: SIGNNUM/n");
return -1;
}
mysigval.sival_ptr=data;
sig=atoi(argv[1]);
sigemptyset(&act.sa_mask);
act.sa_sigaction=SignHandlerNew;
act.sa_flags=SA_SIGINFO;
sigaction(sig,&act,NULL);
while(true){
printf("wait for the signal/n");
sigqueue(getpid(),sig,mysigval);
sleep(2);
}
}
示例2:一个进程向另外一个进程发送信号。注意:发送进程不要将自己进程空间的地址发送给接收进程,因为接收进程接收到地址也访问不到发送进程的地址空间的。
示例2信号接收程序:
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void SignHandlerNew(int signum,siginfo_t *info,void *myact)
{
printf("Get:%d info:%d/n",signum,info->si_int);
}
int main(int argc,char**argv)
{
struct sigaction act;
//
if(argc<2){
printf("usage: signnum/n");
return -1;
}
sigemptyset(&act.sa_mask);
act.sa_sigaction=SignHandlerNew;
act.sa_flags=SA_SIGINFO;
sigaction(atoi(argv[1]),&act,NULL);
while(1)
{
printf("wait for the signal/n");
sleep(2);
}
return 0;
}
示例2信号发送程序:
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc,char**argv)
{
union sigval mysigval;
int iPid,iSignNo,iData;
//
if(argc<4){
printf("usage: pid signnum data/n");
return -1;
}
iPid=atoi(argv[1]);
iSignNo=atoi(argv[2]);
iData=atoi(argv[3]);
mysigval.sival_int=iData;
if(sigqueue(iPid,iSignNo,mysigval)<0)
perror("Send signal fail.");
return 0;
}
5. 计时器与信号
5.1. 睡眠函数
Linux下有两个睡眠函数,原型为:
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
void usleep(unsigned long usec);
函数sleep让进程睡眠seconds秒,函数usleep让进程睡眠usec毫秒。
sleep 睡眠函数内部是用信号机制进行处理的,用到的函数有:
#include <unistd.h>
unsigned int alarm(unsigned int seconds); // 告知自身进程,要进程在seconds秒后自动产生一个//SIGALRM的信号,
int pause(void); // 将自身进程挂起,直到有信号发生时才从pause返回
示例:模拟睡眠3秒:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void SignHandler(int iSignNo)
{
printf("signal:%d/n",iSignNo);
}
int main()
{
signal(SIGALRM,SignHandler);
alarm(3);
printf("Before pause()./n");
pause();
printf("After pause()./n");
return 0;
}
注意:因为sleep在内部是用alarm实现的,所以在程序中最好不要sleep与alarm混用,以免造成混乱。
5.2. 时钟处理
Linux为每个进程维护3个计时器,分别是真实计时器、虚拟计时器和实用计时器。
l 真实计时器计算的是程序运行的实际时间;
l 虚拟计时器计算的是程序运行在用户态时所消耗的时间(可认为是实际时间减掉(系统调用和程序睡眠所消耗)的时间);
l 实用计时器计算的是程序处于用户态和处于内核态所消耗的时间之和。
例如:有一程序运行,在用户态运行了5秒,在内核态运行了6秒,还睡眠了7秒,则真实计算器计算的结果是18秒,虚拟计时器计算的是5秒,实用计时器计算的是11秒。
用指定的初始间隔和重复间隔时间为进程设定好一个计时器后,该计时器就会定时地向进程发送时钟信号。3个计时器发送的时钟信号分别为:SIGALRM,SIGVTALRM和SIGPROF。
用到的函数与数据结构:
#include <sys/time.h>
//获取计时器的设置
//which指定哪个计时器,可选项为ITIMER_REAL(真实计时器)、ITIMER_VITUAL(虚拟计时器、ITIMER_PROF(实用计时器))
//value为一结构体的传出参数,用于传出该计时器的初始间隔时间和重复间隔时间
//如果成功,返回0,否则-1
int getitimer(int which, struct itimerval *value);
//设置计时器
//which指定哪个计时器,可选项为ITIMER_REAL(真实计时器)、ITIMER_VITUAL(虚拟计时器、ITIMER_PROF(实用计时器))
//value为一结构体的传入参数,指定该计时器的初始间隔时间和重复间隔时间
//ovalue为一结构体传出参数,用于传出以前的计时器时间设置。
//如果成功,返回0,否则-1
int setitimer(int which, const struct itimerval *value, struct itimer val *ovalue);
struct itimerval {
struct timeval it_interval; /* next value */ // 重复间隔
struct timeval it_value; /* current value */ // 初始间隔
};
struct timeval {
long tv_sec; /* seconds */ // 时间的秒数部分
long tv_usec; /* microseconds */ // 时间的微秒部分
};
示例:启用真实计时器的进行时钟处理
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void TimeInt2Obj(int imSecond,timeval *ptVal)
{
ptVal->tv_sec=imSecond/1000;
ptVal->tv_usec=(imSecond%1000)*1000;
}
void SignHandler(int SignNo)
{
printf("Clock/n");
}
int main()
{
signal(SIGALRM,SignHandler);
itimerval tval;
TimeInt2Obj(1,&tval.it_value); // 设初始间隔为1毫秒,注意不要为0
TimeInt2Obj(1500,&tval.it_interval); // 设置以后的重复间隔为1500毫秒
setitimer(ITIMER_REAL,&tval,NULL);
while(getchar()!=EOF);
return 0;
}
SIGHUP 终止进程 终端线路挂断
SIGINT 终止进程 中断进程
SIGQUIT 建立CORE文件终止进程,并且生成core文件
SIGILL 建立CORE文件 非法指令
SIGTRAP 建立CORE文件 跟踪自陷
SIGBUS 建立CORE文件 总线错误
SIGSEGV 建立CORE文件 段非法错误
SIGFPE 建立CORE文件 浮点异常
SIGIOT 建立CORE文件 执行I/O自陷
SIGKILL 终止进程 杀死进程
SIGPIPE 终止进程 向一个没有读进程的管道写数据
SIGALARM 终止进程 计时器到时
SIGTERM 终止进程 软件终止信号
SIGSTOP 停止进程 非终端来的停止信号
SIGTSTP 停止进程 终端来的停止信号
SIGCONT 忽略信号 继续执行一个停止的进程
SIGURG 忽略信号 I/O紧急信号
SIGIO 忽略信号 描述符上可以进行I/O
SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
SIGTTOU 停止进程 后台进程写终端
SIGTTIN 停止进程 后台进程读终端
SIGXGPU 终止进程 CPU时限超时
SIGXFSZ 终止进程 文件长度过长
SIGWINCH 忽略信号 窗口大小发生变化
SIGPROF 终止进程 统计分布图用计时器到时
SIGUSR1 终止进程 用户定义信号1
SIGUSR2 终止进程 用户定义信号2
SIGVTALRM 终止进程 虚拟计时器到时
signal()函数的更多相关文章
- Linux 信号(二)—— signal 函数
弗洛伊德认为:要解决这些苦恼,当事人就要通过回忆并理解自己早期的童年经历,来获得对潜意识冲突的顿悟.弗洛伊德的疗法被称为“精神分析” (psychoanalysis),在 20 世纪的很长一段时间被心 ...
- Linux 信号详解一(signal函数)
信号列表 SIGABRT 进程停止运行 SIGALRM 警告钟 SIGFPE 算述运算例外 SIGHUP 系统挂断 SIGILL 非法指令 SIGINT 终端中断 SIGKILL 停止进程(此信号不能 ...
- 信号之signal函数
UNIX系统的信号机制最简单的接口是signal函数.signal函数的功能:为指定的信号安装一个新的信号处理函数. #include <signal.h> void (*signal(i ...
- signal函数、sigaction函数及信号集(sigemptyset,sigaddset)操作函数
信号是与一定的进程相联系的.也就是说,一个进程可以决定在进程中对哪些信号进行什 么样的处理.例如,一个进程可以忽略某些信号而只处理其他一些信号:另外,一个进程还可以选择如何处理信号.总之,这些总与特定 ...
- Signal ()函数详细介绍 Linux函数
http://blog.csdn.net/ta893115871/article/details/7475095 Signal ()函数详细介绍 Linux函数 signal()函数理解 在<s ...
- 如何理解signal函数声明
Signal函数用起来其实很简单,但是回头看看他的声明,相信会有很多人表示费解.自己也在这个问题中纠结了好几年了,今天终于弄明白,很是兴奋,一起分享一下. 先看函数原型:void (*signal(i ...
- Signal ()函数详细介绍 Linux函数(转)
Signal ()函数详细介绍 Linux函数 收藏人:紫火神兵 2012-09-27 | 阅:5659 转:22 | 来源 | 分享 signa ...
- UNIX环境高级编程——信号基本概述和signal函数
一.为了理解信号,先从我们最熟悉的场景说起:1. 用户输入命令,在Shell下启动一个前台进程.2. 用户按下Ctrl-C,这个键盘输入产生一个硬件中断.3. 如果CPU当前正在执行这个进程的代码,则 ...
- POSIX信号和自定义signal函数
一.信号的概念 信号(signal)就是告知某个进程发生了某个事件的通知:信号通常是异步发生的,也就是说接受信号的进程不知道信号的准确 发生时刻:信号可以(1)由一个进程发给另一个进程:(2)由内核发 ...
随机推荐
- 生产环境的redis高可用集群搭建
这里只是总结一下安装步骤 如果要了解redis集群高可用的原理,推荐仔细看一遍配置文件示例http://download.redis.io/redis-stable/redis.conf,源码包里也有 ...
- php set_include_path
string set_include_path ( string $new_include_path ) 为当前脚本设置 include_path 运行时的配置选项. Example #2 添加到in ...
- 快速获取Windows系统上的国家和地区信息
Windows系统上包含了200多个国家和地区的数据,有时候编程需要这些资料.以下代码可以帮助你快速获取这些信息.将Console语句注释掉,可以更快的完成分析. static void Main(s ...
- emacs 快捷键笔记
C-d C-aM-aC-eM-e===复制黏贴M-d kill-wordM-del backward-kill-wordM-k kill-sentenceC-x del back ...
- ArrayList集合的语句示例
namespace ArrayList集合的语句示例{ class Program { static void Main(string[] args) { ...
- How does browsersync work?
How Does BrowserSync Work? BrowserSync starts a small web server. If you’re already using a local we ...
- 通过javascript把图片转化为字符画
1.获取上传图片对象数据 Javascript无法直接获取本地上传的图片的数据,html5可以解决这一问题 .html5里面的FileReader interface可以把图片对象的数据读到内存,然后 ...
- Java RGB数组图像合成 ImageCombining (整理)
/** * Java RGB数组图像合成 ImageCombinning (整理) * * 2016-1-2 深圳 南山平山村 曾剑锋 * * 注意事项: * 1.本程序为java程序,同时感谢您花费 ...
- BPMN这点事-BPMN扩展元素
什么是BPMN扩展元素?我们为什么要从BPMN元素中界定出一个扩展元素的子集?BPMN扩展元素是我们平时使用频率不高的BPMN元素,这些元素更多的面向开发人员而不是业务人员,它们强调流程执行的细节,例 ...
- 06day2
蠕虫游戏 模拟 [问题描述] 蠕虫是一个古老的电脑游戏,它有许多版本.但所有版本都有一个共同规则:操纵一条蠕虫在屏幕上转圈,并试着去避免撞到自己或障碍物. 这里我们将模拟一个简单的版本.游戏将在 50 ...