宜春招聘网站开发区招工,公司网站做的一样算不算侵权6,电子商务网站建设需要哪些工作,人才网站建设的目标目录 一、信号的概念 二、定时器
1. alarm函数 2. setitimer函数
3.signal和sigaction函数
三、使用SIGCHLD信号实现回收子进程 一、信号的概念 概念#xff1a;信号是在软件层次上对中断机制的一种模拟#xff0c;是一种异步通信方式 。所有信号的产生及处理全部都是由内…目录 一、信号的概念 二、定时器
1. alarm函数 2. setitimer函数
3.signal和sigaction函数
三、使用SIGCHLD信号实现回收子进程 一、信号的概念 概念信号是在软件层次上对中断机制的一种模拟是一种异步通信方式 。所有信号的产生及处理全部都是由内核完成的。
信号处理方式 1 缺省方式 2 忽略信号 3 捕捉信号
在信号处理中通常有三种处理方式 缺省方式Default这是操作系统针对每种信号定义的默认行为。对于大多数信号缺省行为是终止进程。例如SIGINT 的缺省行为是终止进程。 忽略信号Ignore这种方式下进程对收到的信号不做任何响应。这意味着当进程收到指定信号时不会采取任何动作。这通常用于某些不需要处理的信号或者是在某些特定情况下临时禁用信号处理器。 捕捉信号Catch这种方式下进程定义一个信号处理函数用于处理特定信号。当进程收到指定信号时会调用这个信号处理函数。这允许程序员自定义对信号的处理方式例如收到 SIGINT 时执行特定的操作而不是终止进程。 在如下代码中使用了第三种方式即捕捉信号。通过调用 signal(SIGINT, handle)定义了一个信号处理函数 handle用于处理 SIGINT 信号。当程序收到 SIGINT 信号时会调用 handle 函数来处理它而不是按照默认的方式终止进程。 注意typedef void (*sighandler_t)(int);不能少
#includestdio.h
#includeunistd.h
#includestring.h
#includesignal.h
#includestdlib.htypedef void (*sighandler_t)(int);
sighandler_t oldact;void handle(int sig)
{printf(I cath the SIGINT\n);signal(SIGINT,oldact);
}int main()
{oldact signal(SIGINT,handle);while(1){sleep(1);}return 0;
}代码注释
使用 signal 函数来设置信号处理函数并捕获 SIGINT 信号通常由键盘上的CtrlC组合键发送。这段代码的功能是在收到 SIGINT 信号时打印一条消息并重新设置 SIGINT 信号的处理函数为先前的处理函数。下面是代码的简要解释signal(SIGINT, handle)这行代码设置了 SIGINT 信号的处理函数为 handle。
在收到 SIGINT 信号时系统将调用 handle 函数来处理该信号。handle 函数这是 SIGINT 信号的处理函数。当程序收到 SIGINT 信号时会调用这个函数并打印一条消息 I catch the SIGINT。
然后它将信号的处理函数重新设置为 oldact这样可以恢复先前的信号处理函数。oldact这是一个全局变量用于保存先前 SIGINT 信号的处理函数。while(1) 循环这是一个无限循环程序在这里持续运行每次循环睡眠1秒钟。
为什么“它将信号的处理函数重新设置为 oldact这样可以恢复先前的信号处理函数” 先前的处理函数在这里就是系统的默认状态即CTRLC可以终止信号。
在这段代码中oldact 保存了先前 SIGINT 信号的处理函数。
当程序收到 SIGINT 信号时handle 函数会被调用。
在 handle 函数中执行了 signal(SIGINT, oldact)这样做的目的是将 SIGINT 信号的处理函数重新设置为先前保存的处理函数 oldact。这样做的原因是为了确保在 handle 函数执行完毕后再次收到 SIGINT 信号时会调用先前的处理函数而不是再次调用 handle 函数。
这样可以恢复程序在接收 SIGINT 信号时的默认行为或者是由用户自定义的其他行为。 通过在调用 signal 函数时将 oldact 作为第二个参数传递进去可以获取先前的信号处理函数。然后你可以在需要的时候使用这个指针来重新设置信号处理函数从而恢复到先前的处理方式。
在 signal 函数中oldact 是一个指向先前信号处理函数的指针。signal 函数的原型如下void (*signal(int signum, void (*handler)(int)))(int);它返回了一个指向先前信号处理函数的指针。
这个指针的类型是 sighandler_t它是一个函数指针类型它指向一个接受 int 参数并返回 void 的函数。当程序启动时通常会有一些默认的信号处理方式。例如对于 SIGINT 信号通常由用户按下 CtrlC 发送默认情况下会终止程序。 当你调用 signal(SIGINT, handle) 时你指定了一个自定义的信号处理函数 handle用于处理 SIGINT 信号。在这之前如果有其他函数被注册为 SIGINT 信号的处理函数那么 signal 函数会返回这个先前的处理函数并将其保存在 oldact 变量中。 之后如果你想要恢复先前的处理方式你可以调用 signal(SIGINT, oldact)这样 SIGINT 信号会再次被先前的处理函数处理而不是你自定义的 handle 函数。
常用信号 信号名 含义 默认操作 SIGKILL 该信号用来结束进程并且不能被捕捉和忽略 终止 SIGSTOP 该信号用于暂停进程并且不能被捕捉和忽略 暂停进程 SIGTSTP 该信号用于暂停进程用户可键入SUSP字符( 通常是Ctrl-Z)发出这个信号 暂停进程 SIGCONT 该信号让进程进入运行态 继续运行 SIGALRM 该信号用于通知进程定时器时间已到 终止 SIGUSR1/2 该信号保留给用户程序使用 终止 SIGCHLD 是子进程状态改变发给父进程的。 忽略 信号名 含义 默认操作 SIGHUP 该信号在用户终端关闭时产生通常是发给和该 终端关联的会话内的所有进程 终止 SIGINT 该信号在用户键入INTR字符(Ctrl-C)时产生内 核发送此信号送到当前终端的所有前台进程 终止 SIGQUIT 该信号和SIGINT类似但由QUIT字符(通常是 Ctrl-\)来产生 终止 SIGILL 该信号在一个进程企图执行一条非法指令时产生 终止 SIGSEV 该信号在非法访问内存时产生如野指针、缓 冲区溢出 终止 SIGPIPE 当进程往一个没有读端的管道中写入时产生代 表“管道断裂” 终止 二、定时器
1. alarm函数
alarm 函数的原型如下 unsigned int alarm(unsigned int seconds); 它接受一个无符号整数参数 seconds表示定时器的超时时间单位是秒。调用 alarm 函数会设置一个定时器在指定的秒数之后会产生 SIGALRM 信号。
#include stdio.h
#include unistd.h
#include signal.hvoid alarm_handler(int signum)
{printf(Alarm signal received!\n);}int main()
{signal(SIGALRM, alarm_handler);alarm(5);printf(Waiting for alarm...\n);while (1) {sleep(1);}return 0;
}alarm(5) 函数调用设置了一个5秒的定时器。但是在程序调用 alarm(5) 设置定时器之后程序会立即继续执行下一条语句而不会等待5秒钟。这意味着在调用 alarm(5) 之后立即执行了 printf(Waiting for alarm...\n); 这行代码所以会立即打印出 Waiting for alarm...。然后程序会进入 while 循环在那里它会等待5秒钟直到定时器超时并产生 SIGALRM 信号。
因此程序执行的步骤是这样的
执行 alarm(5); 设置一代码个5秒的定时器。立即执行 printf(Waiting for alarm...\n);打印 Waiting for alarm...。进入 while 循环程序会等待5秒钟。定时器超时产生 SIGALRM 信号调用 alarm_handler 函数。打印 Alarm signal received!\n。程序继续执行 while 循环中的其他代码。 2. setitimer函数 int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value); 功能定时的发送alarm信号参数which ITIMER_REAL以逝去时间递减。发送SIGALRM信号、ITIMER_VIRTUAL: 计算进程用户模式执行的时间。 发送SIGVTALRM信号new_value 负责设定 timout 时间 old_value 存放旧的timeout值一般指定为NULLstruct itimerval{struct timeval it_interval; // 闹钟触发周期struct timeval it_value; // 闹钟触发时间};struct timeval{time_t tv_sec; /* seconds */suseconds_t tv_usec; /* microseconds */};
#includesys/time.h
#includestdio.h
#includestdlib.h
#includestring.h
#includesignal.hvoid timer_handler(int signum)
{printf(Timer expired!\n);
}int main()
{struct itimerval timer;struct sigaction act;act.sa_handler timer_handler;act.sa_flags 0;sigemptyset(act.sa_mask);timer.it_value.tv_sec 5; // 5秒后定时器启动timer.it_value.tv_usec 0;timer.it_interval.tv_sec 1; // 间隔1秒timer.it_interval.tv_usec 0;sigaction(SIGALRM, act,NULL);if (setitimer(ITIMER_REAL, timer, NULL) -1){perror(setitimer);exit(EXIT_FAILURE);}while (1){sleep(1);}return 0;
}
定义了一个信号处理函数 timer_handler用于在定时器到期时打印 Timer expired!。创建了一个 struct itimerval 结构体变量 timer并设置了定时器的参数it_value 成员设置为 5 秒表示定时器将在 5 秒后启动。
it_interval 成员设置为 1 秒表示定时器在启动后每隔 1 秒触发一次。
创建了一个 struct sigaction 结构体变量 act并设置了其中的成员sa_handler 成员设置为 timer_handler 函数表示 SIGALRM 信号的处理函数为 timer_handler。
sa_flags 设置为 0表示不设置特殊标志。
sa_mask 使用 sigemptyset 函数清空表示在执行 timer_handler 函数期间不阻塞任何信号。
使用 sigaction 函数将 SIGALRM 信号的处理函数设置为 timer_handler 函数。使用 setitimer 函数设置实时定时器并传入 timer 结构体启动定时器。进入一个无限循环程序将持续运行每隔 1 秒调用 sleep(1) 函数等待定时器的触发。总的来说这段代码实现了一个定时器在程序启动 5 秒后启动并且每隔 1 秒触发一次定时器在定时器触发时打印一条消息。
3.signal和sigaction函数
signal函数
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能捕捉信号执行自定义函数
返回值成功时返回原先的信号处理函数失败时返回SIG_ERR
参数signo 要设置的信号类型handler 指定的信号处理函数: SIG_DFL代表缺省方式; SIG_IGN 代表忽略信号; 系统建议使用sigaction函数因为signal在不同类unix系统的行为不完全一样。
sigaction函数
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
struct sigaction {void (*sa_handler)(int);void (*sa_sigaction)(int, siginfo_t *, void *);sigset_t sa_mask;int sa_flags;void (*sa_restorer)(void);
}
参数
signum处理的信号
act,oldact: 处理信号的新行为和旧的行为是一个sigaction结构体。sigaction结构体成员定义如下
sa_handler 是一个函数指针其含义与 signal 函数中的信号处理函数类似
sa_sigaction 另一个信号处理函数它有三个参数可以获得关于信号的更详细的信息。
sa_flags参考值如下
SA_SIGINFO使用 sa_sigaction 成员而不是 sa_handler 作为信号处理函数
SA_RESTART使被信号打断的系统调用自动重新发起。
SA_RESETHAND信号处理之后重新设置为默认的处理方式。
SA_NODEFER使对信号的屏蔽无效即在信号处理函数执行期间仍能发出这个信号。
re_restorer是一个已经废弃的数据域三、使用SIGCHLD信号实现回收子进程
SIGCHLD的产生条件 1子进程终止时 2子进程接收到SIGSTOP信号停止时 3子进程处在停止态接受到SIGCONT后唤醒时
#includestdio.h
#includestdlib.h
#includeunistd.h
#includesys/wait.h
#includesignal.h
#includestring.h
#includeerrno.hvoid handle(int sig)
{wait(NULL);printf(GET sig %d\n,sig);
}
int main()
{pid_t pid;struct sigaction act;act.sa_handler handle;act.sa_flags 0;sigemptyset(act.sa_mask);pid fork();if(pid 0){//wait(NULL);sigaction(SIGCHLD,act,NULL);while(1){printf(this is father process\n);sleep(1);}}else if(pid 0){sleep(5);exit(0);}else{perror(fork);return 0;}
}这段代码创建了一个父子进程并使用 wait 函数等待子进程结束。
在父进程中设置了 SIGCHLD 信号的处理函数为 handle 函数用于处理子进程终止的信号。
具体来说父进程会周期性地打印一条消息而子进程在启动后会等待 5 秒后自行退出。下面是这段代码的执行逻辑程序开始执行父进程调用 fork 创建了一个子进程。父进程中如果 fork 成功返回大于 0 的值则进入了一个无限循环不断地打印 this is father process并在其中使用 sigaction 函数设置了 SIGCHLD 信号的处理函数为 handle 函数。子进程中如果 fork 成功返回 0则进入了 if (pid 0) 的分支子进程会休眠 5 秒后自行退出。如果 fork 出错返回小于 0 的值则父进程中输出错误信息并退出。当子进程结束时父进程会收到 SIGCHLD 信号进而调用 handle 函数来处理。在 handle 函数中调用 wait 函数等待子进程结束并打印 GET sig xx 的信息其中 xx 是接收到的信号值。总的来说这段代码通过信号处理机制实现了在父进程中对子进程的终止进行处理。
wait(NULL)
当一个父进程调用 wait(NULL) 时它会发生以下事情
1. **阻塞父进程**如果没有任何子进程已经结束wait(NULL) 会阻塞父进程直到至少有一个子进程结束。 2. **回收子进程**一旦有子进程结束wait(NULL) 会回收该子进程的资源。这意味着操作系统会清理与该子进程相关的所有资源比如内存和进程控制块。 3. **不指定子进程**由于 wait(NULL) 不指定等待特定的子进程它适用于等待任何一个子进程。如果需要等待特定的子进程可以使用 waitpid(pid, status, options) 函数其中 pid 是特定子进程的进程号。linux waitnull函数_wait(null)-CSDN博客https://blog.csdn.net/weixin_44652882/article/details/134363936