信号通信
1.信号の概要
信号は、ソフトウェアレベルでの割り込みメカニズムのシミュレーションです。原則として、プロセスはシグナルを受信し、プロセッサーは割り込み要求を受信していると言えます。シグナルは非同期です。プロセスは、どの操作でもシグナルの到着を待つ必要はありません。信号は、ユーザー空間プロセスとカーネルプロセスの間の相互作用を直接実行でき、カーネルプロセスは、それを使用して、どのシステムイベントが発生したかをユーザー空間プロセスに通知することもできます。プロセスの状態を知らなくても、いつでもプロセスに送信できます。プロセスが現在実行状態にない場合、シグナルはプロセスが実行を再開するまでカーネルによって保存されてから渡されます。シグナルがプロセスによってブロックされるように設定されている場合、シグナルの送信はブロックされるまで遅延されますキャンセルされるとプロセスに渡されます。
シグナルは、プロセス間通信メカニズムにおける唯一の非同期通信メカニズムです。このメカニズムは、シグナルを受信したプロセスに何が起こったかを通知する非同期通知と考えることができます。信号イベントは、ハードウェアソース(キーストロークやハードウェア障害など)とソフトウェアソース(kill()、raise()、alarm()、setitimer()、sigqueue()など)、およびいくつかの不正な操作から生成できます。
プロセスは3つの方法でシグナルに応答できます。
- シグナルを無視:シグナルに対して何もしません。SIGKILLおよびSIGSTOPシグナルは無視できません
- 信号のキャプチャ:信号処理関数を定義し、信号が発生したときに対応する処理関数を実行します
- デフォルトモード:Linuxは、次の表に示すように、各信号に対してデフォルトの操作を提供します
信号名 | 意味 | デフォルトのアクション |
---|---|---|
SIGHUP | ユーザー端末接続が終了すると送信され、同じセッションの各プロセスが制御端末に関連付けられなくなったことを通知します | プロセスを終了する |
SIGINT | INTR文字が入力されると発生し(Ctrl + C)、フォアグラウンドプロセスの各プロセスに送信されます。 | プロセスを終了する |
シグキット | SIGINTに似ていますが、QUIT文字(Ctrl + \)を使用して制御します | プロセスを終了する |
密閉する | プロセスが不正な命令を実行しようとしたときに発行されます | プロセスを終了する |
SIGFPE | 致命的な算術演算が発生したときに発行されます | プロセスを終了する |
シギル | プログラムの実行をすぐに終了するために使用され、ブロック、処理、または無視することはできません | プロセスを終了する |
SIGALARM | タイマーが切れると発生します | プロセスを終了する |
SIGSTOP | プロセスを一時停止するために使用され、ブロック、処理、または無視することはできません | プロセスを一時停止します |
SIGTSTP | ユーザーがSUSP文字を入力したときに発行されるプロセスをインタラクティブに停止するために使用されます(Ctrl + Z) | プロセスを終了する |
SIGCHLG | 子プロセスの状態が変化すると、親プロセスがこのシグナルを受け取ります | 無視する |
2.信号相関関数
2.1シグナル送信:kill()とraise()
kill()関数はkill systemコマンドと同じです。プロセスまたはプロセスグループにシグナルを送信できます(kill systemコマンドはkill()関数によって実装されます)。この関数は、プロセスを終了するだけでなく、他のシグナルをプロセスに送信することもできます。
raise()関数は、プロセスがそれ自体にシグナルを送信することのみを許可します。
/*****kill()函数*****/
函数原型:int kill(pid_t pid, int sig)
传 入 值:pid -->正数:发送信号给进程号为pid的进程
--> 0:信号被发送到所有和当前进程在同一个进程组的进程
-->-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
-->小于-1:信号发送给进程组号为-pid的每一个进程
sig 信号类型
返 回 值:成功返回0;失败返回-1
/*****raise()函数*****/
函数原型:int raise(int sig)
传 入 值:sig 信号类型
返 回 值:成功返回0;失败返回-1
プログラム例
/*****kill_raise.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(){
pid_t pid;
int ret;
if((pid == fork()) < 0){
//创建子进程
printf("Fork error\n");
exit(-1);
}
if(pid == 0){
/*在子进程中使用raise()函数发出SIGSTOP信号,使子进程暂停*/
printf("child(pid: %d) is waiting for any signal!\n",getpid());
raise(SIGSTOP);
exit(0);
}else{
/*在父进程中收集子进程的状态,并调用kill()函数发送信号*/
if((waitpid(pid,NULL,WNOHANG)) == 0){
kill(pid,SIGKILL);
printf("parent kill child process %d\n",pid);
}
waitpid(pid,NULL,0);
exit(0);
}
}
プログラムの結果は次のとおりです
linux@linux-virtual-machine:~/andy/proc$ ./kill_raise
child(pid:4877) is waiting for any signal!
parent kill child process 4877
2.2タイマー信号:alarm()およびpause()
alarm()はアラーム関数とも呼ばれ、プロセスのタイマーを設定できます。タイマーで指定された時間が経過すると、SIGALARMシグナルがプロセスに送信されます。プロセスは1つのアラーム時間しか持つことができないことに注意する必要があります。alarm()を呼び出す前にアラーム時間が設定されている場合、以前のアラーム時間は新しい値に置き換えられます。
pause()は、シグナルが受信されるまで呼び出しプロセスを一時停止するために使用されます。
/*****alarm()函数*****/
函数原型:unsigned int alarm(unsigned int seconds)
传 入 值:seconds 指定秒数,系统经过seconds秒后向该进程发送SIGALARM信号
返 回 值:成功:如果调用此函数前,进程中已经设置了闹钟时间,则返回上一个闹钟剩余的时间,否则返回0
失败:返回-1
/*****pause()函数*****/
函数原型:int pause(void)
返 回 值:-1 并且把errno值设为EINTR
プログラム例
/*****alarm_pause.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
alarm(5);
pause();
printf("I have been waken up\n"); //此语句不会被执行
}
プログラムの結果は次のとおりです
linux@linux-virtual-machine:~/andy/proc$ ./alarm_pause
Alarm clock //SIGALARM信号默认处理函数打印
2.3信号設定:signal()およびsigaction()
信号処理には主に2つの方法があります。1つは単純なsignal()関数を使用する方法で、もう1つはsigaction()を使用する方法です。
signal()関数は、信号タイプと信号処理関数を指定するだけで済みます。主に最初の32種類の非リアルタイム信号の処理に使用され、情報の信号送信をサポートしていません。
sigaction()関数は、signal()関数よりも堅牢で用途が広いです。
/*****signal()函数*****/
函数原型:typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
传 入 值:signum 指定信号代码
handler -->SIG_IGN 忽略该信号
-->SIG_DFL 采用系统默认方式处理信号
-->自定义的信号处理函数
返 回 值:成功:返回以前的信号处理函数
失败:返回-1
/*****sigaction()函数*****/
函数原型:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
传 入 值:signum 信号类型,除SIGKILL和SIGSTOP之外的任何一个信号
act 指向sigaction结构体的指针,包含对特点信号的处理
oldact 保存信号原先的处理方式
返 回 值:成功返回0;失败返回-1
//sigaction结构体的定义
struct sigaction{
void (*sa_handler)(int signo); //函数指针,指向信号处理函数
sigset_t sa_mask; //信号集合,用来指定在信号处理函数执行过程中哪些信号被屏蔽
int sa_flags; //信号处理相关的各种标志位
void (*sa_restore)(void);
}
signal()サンプルプログラム
/*****signal.c*****/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void my_func(int sign_no){
//自定义信号处理函数
if(sign_no == SIGINT)
printf("I have got SIGINT\n");
else if(sign_no == SIGQUIT)
printf("I have got SIGQUIT\n");
}
int main(){
printf("Waiting for signal SIGINT or SIGQUIT...\n");
signal(SIGINT,my_func);
signal(SIGQUIT,my_func);
pause();
exit(0);
}
プログラムの結果は次のとおりです
linux@linux-virtual-machine:~/andy/proc$ ./signal
Waiting for signal SIGINT or SIGQUIT...
I have got SIGINT (按 ctrl + c 组合键)
linux@linux-virtual-machine:~/andy/proc$ ./signal
Waiting for signal SIGINT or SIGQUIT...
I have got SIGQUIT (按 ctrl + \ 组合键)
同じ機能を実現するsigaction()サンプルプログラム
/*****sigaction.c*****/
//头文件省略
//自定义信号处理函数同以上实例
int main(){
struct sigaction action;
/*sigaction结构初始化*/
sigaction(SIGINT,0,&action);
action.sa_handler = my_func;
sigaction(SIGINT,&action,0);
sigaction(SIGQUIT,0,&action);
action.sa_handler = my_func;
sigaction(SIGQUIT,&action,0);
printf("Waiting for signal SIGINT or SIGQUIT...\n");
pause();
exit(0);
}