私の連絡先情報
郵便メール:
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
シグナル (シグナル) は、プロセス間でメッセージを送信する方法です。イベントの発生をプロセスに通知するために使用されますが、プロセスにデータを渡すことはできません。
シェルでシグナルが生成される理由は数多くあります。kill
そしてkillall
信号を送信するコマンド:
kill -信号的类型 进程编号
killall -信号的类型 进程名
信号名 | 信号値 | デフォルトの処理アクション | シグナリングの理由 |
---|---|---|---|
SIGHUP | 1 | あ | 端末がハングするか、制御プロセスが終了する |
シギント | 2 | あ | キーボード割り込み Ctrl+c |
終了 | 3 | C | キーボードのエスケープキーが押されたとき |
シギル | 4 | C | 違法な指導 |
シグトラップ | 5 | C | ブレークポイント命令 |
シガバート | 6 | C | abort(3) によって発行されたアボート信号 |
シグバス | 7 | C | バスエラー |
SIGFPE | 8 | C | 浮動小数点例外 |
シグナルキル | 9 | あ | kill -9 はプロセスを強制終了します。このシグナルは捕捉および無視できません。 |
SIGUSR1 | 10 | あ | ユーザー定義信号 1 |
SIGSEGV | 11 | C | 無効なメモリ参照 (範囲外の配列、NULL ポインタ操作) |
SIGUSR2 | 12 | あ | ユーザー定義信号 2 |
SIGPIPE の | 13 | あ | 読み取りプロセスを行わずにデータをパイプに書き込みます |
シガルム | 14 | あ | 目覚まし時計信号、alarm() 関数によって送信される信号 |
シグナルターム | 15 | あ | 終了信号、デフォルトで送信される信号 |
SIGSTKFLT | 16 | あ | スタックエラー |
シグナル | 17 | B | 子プロセスの終了時に発行されます |
シグナル継続 | 18 | だ | 停止したプロセスを再開する |
シグナルストップ | 19 | だ | プロセスの停止 |
シグナルTP | 20 | だ | ターミナルでストップキーを押す |
署名 | 21 | だ | バックグラウンドプロセスによる端末の読み取り要求 |
シグトゥ | 22 | だ | バックグラウンドプロセスが端末への書き込みを要求します |
シグルグ | 23 | B | 緊急状態の検出 (ソケット) |
SIGXCPU | 24 | C | CPU時間制限を超えました |
SIGGFSZ の | 25 | C | ファイルサイズ制限を超えました |
信号 | 26 | あ | 仮想クロック信号 |
シグプロフ | 27 | あ | クロック信号を解析する |
シグウィンチ | 28 | B | ウィンドウサイズの変更 |
シグナルポール | 29 | B | ポーリング(Sys V) |
SIGPWR | 30 | あ | 停電 |
シグシス | 31 | C | 不正なシステムコール |
A のデフォルトのアクションはプロセスを終了することです。
B のデフォルトのアクションは、この信号を無視することです。
C のデフォルトのアクションは、プロセスを終了し、カーネル イメージ ダンプを実行することです。
D のデフォルトのアクションはプロセスを停止することですが、停止状態に入ったプログラムは実行を継続できます。
プロセスがシグナルを処理するには 3 つの方法があります。
signal()
関数は、プログラムが信号を処理する方法を設定できます。
関数宣言:
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
パラメータの説明:
sig
:キャプチャする信号を指定します。func
: 信号処理関数へのポインタ。処理関数は、キャプチャされた信号番号である整数パラメータを受け取る必要があります。SIG_DFL
:SIG_DFL マクロは、デフォルトの信号処理方法を表します。使用SIG_DFL
としてsignal
関数の 2 番目のパラメーターは、システムのデフォルトの処理方法が信号に使用されることを示します。SIG_IGN
:SIG_IGN マクロは信号を無視することを意味します。使用SIG_IGN
としてsignal
関数の 2 番目のパラメーターは、プロセスがシグナルを受信したときにそれを無視し、処理を実行しないことを示します。これにより、特定の状況でプロセスが予期せず終了したり中断されたりするのを防ぐことができます。SIG_ERR
:SIG_ERR
マクロはエラーを示すために使用されます。それはそうではありませんsignal
関数の 2 番目のパラメータは代わりに次のように使用されます。signal
関数の戻り値は、呼び出しが失敗したことを示します。もしsignal
関数の呼び出しが失敗した場合は、戻り値が返されます。SIG_ERR
。これは通常、検出と処理に使用されますsignal
関数呼び出しでエラーが発生しました。サービス プログラムはバックグラウンドで実行されており、プロセスを強制終了すると突然終了し、その後の処理が行われないため、サービス プログラムを強制終了することはお勧めできません。
サービス プログラムにシグナルを送信すると、シグナルを受信した後、サービス プログラムは関数を呼び出し、関数内にアフターマス コードを書き込むため、プログラムは計画的に終了できます。
サービス プログラムに 0 のシグナルを送信すると、プログラムが生きているかどうかを検出できます。
Linux オペレーティング システムが提供するのは、 kill
そしてkillall
コマンドはプログラムにシグナルを送信します。プログラム内では、次のコマンドを使用できます。kill()
ライブラリ関数は他のプロセスにシグナルを送信します。
関数宣言:
int kill(pid_t pid, int sig);
kill()
関数はパラメータを受け取りますsig
指定された信号がパラメータに渡されますpid
指定されたプロセス。
パラメータ pid
いくつかの状況があります。
pid > 0
シグナルを次のようにプロセスに渡しますpid
プロセス。pid = 0
現在のプロセスと同じプロセス グループ内のすべてのプロセスにシグナルを渡します。これは、親プロセスが子プロセスにシグナルを送信するためによく使用されます。この動作はシステムの実装に依存することに注意してください。pid < -1
のプロセス グループ ID にシグナルを渡します。|pid|
すべてのプロセスの。pid = -1
シグナルを送信する許可を持つすべてのプロセスにシグナルを渡しますが、シグナルを送信したプロセスには渡しません。プロセスを終了するには 8 つの方法があり、そのうち 5 つは通常の終了です。
main()
機能用return
戻る;exit()
関数;_exit()
または_Exit()
関数;return
戻る;pthread_exit()
戻る;異常終了するには次の 3 つの方法があります。
abort()
関数の中止。存在する main()
関数では、return
終了ステータスでない場合、戻り値は終了ステータスです。return
声明または電話exit()
の場合、プロセスの終了ステータスは 0 になります。
シェルで、プロセスの終了ステータスを表示します。
echo $?
プロセスを正常に終了する3つの関数(exit()
そして_Exit()
ISO Cで規定されており、_exit()
POSIX で指定されています):
void exit(int status);
void _exit(int status);
void _Exit(int status);
status
プロセスの終了ステータス。
return
関数が戻るときに、ローカル オブジェクトのデストラクターが呼び出されるように指定します。main()
機能中return
グローバル オブジェクトのデストラクターも呼び出されます。exit()
プロセスを終了することを示します。ローカル オブジェクトのデストラクターは呼び出されず、グローバル オブジェクトのデストラクターのみが呼び出されます。_exit()
そして_Exit()
直接終了すると、クリーンアップ作業は実行されません。プロセスは利用可能です atexit()
機能登録により終了する機能(最大32個)は、これらの機能が終了します。exit()
自動的に呼び出されます。
int atexit(void (*function)(void));
exit()
終了関数が呼び出される順序は登録時とは逆になります。
system()
この関数は、プログラムを実行するための簡単なメソッドを提供し、実行する必要があるプログラムとパラメーターを文字列として渡します。system()
ただ機能するだけ。
関数宣言:
int system(const char * string);
system()
さらに厄介なのは関数の戻り値です。
system()
関数はゼロ以外を返します。system()
この関数は 0 を返します。system()
関数はゼロ以外を返します。exec
関数ファミリーは、プロセス内でプログラム (バイナリまたはシェル スクリプト) を呼び出す別の方法を提供します。
exec
関数ファミリーは次のように宣言されます。
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
知らせ:
errno
真ん中。exec
その後、呼び出されたプログラムが呼び出し元のプログラムを置き換えます。exec
関数の後のコードは実行されません。execl()
そしてexecv()
、その他はほとんど使用されません。Linux システム全体のすべてのプロセスはツリー構造になっています。
使用pstree
次のコマンドを使用してプロセス ツリーを表示できます。
pstree -p 进程编号
各プロセスには、負でない整数で表される一意のプロセス ID があります。プロセス ID は一意ですが、再利用できます。プロセスが終了すると、そのプロセス ID が再利用の候補になります。 Linux は遅延再利用アルゴリズムを使用しているため、新しく作成されたプロセスの ID は、最近終了したプロセスで使用されていた ID とは異なります。これにより、新しいプロセスが同じ ID を使用して終了したプロセスと間違われるのを防ぎます。
プロセスIDを取得する関数:
pid_t getpid(void); // 获取当前进程的ID。
pid_t getppid(void); // 获取父进程的ID。
既存のプロセスは呼び出すことができますfork()
関数は新しいプロセスを作成します。
関数宣言:
pid_t fork(void);
によるfork()
新しく作成されたプロセスを子プロセスと呼びます。
fork()
この関数は 1 回呼び出されますが、2 回戻ります。 2 つの戻り値の違いは、子プロセスの戻り値が 0 であるのに対し、親プロセスの戻り値は新しく作成された子プロセスのプロセス ID であることです。
子プロセスと親プロセスは実行を継続します。fork()
その後のコードは、子プロセスは親プロセスのコピーです。子プロセスには、親プロセスのデータ領域、ヒープ、およびスタックのコピーがあります (注: 子プロセスはコピーを所有し、親プロセスと共有されません)。
fork()
それ以降、親プロセスと子プロセスの実行順序は不定になります。
fork()
、子プロセスにこれらのリクエストを処理させ、親プロセスは次の接続リクエストを待ち続けます。fork()
帰ったらすぐに電話exec
。fork()
1 つの特徴は、親プロセスで開かれたファイル記述子が子プロセスにコピーされ、親プロセスと子プロセスが同じファイル オフセットを共有することです。
親プロセスと子プロセスが、いかなる同期も行わずに、同じ記述子が指すファイルに書き込む場合、それらの出力が互いに混合される可能性があります。
この時点では、データが 100,000 行しかないことがわかります。
この時点で 200,000 行のデータが存在するはずですが、ファイルの書き込み操作がアトミックではないため、2 つのプロセスが同時にファイルの異なる部分を書き込もうとする可能性があります。データが相互に干渉し合うため、書き込みが失敗します。
vfork()
関数呼び出しと戻り値は同じですfork()
同じですが、セマンティクスが異なります。
vfork()
この関数は、目的が次のような新しいプロセスを作成するために使用されます。exec
子プロセスがすぐに呼び出しを行うため、親プロセスのアドレス空間をコピーしない新しいプログラムexec
, そのため、親プロセスのアドレス空間は使用されません。子プロセスが親プロセスのアドレス空間を使用すると、不明な結果が発生する可能性があります。
vfork()
そしてfork()
もう 1 つの違いは次のとおりです。vfork()
子プロセスが最初に実行されていることを確認し、子プロセスで呼び出します。exec
またはexit
その後、親プロセスが動作を再開します。
オペレーティング システムでは、ゾンビ プロセスとは、終了したものの親プロセスが終了ステータスをまだ読み取っていない子プロセスを指します。ゾンビ プロセスは実行されていませんが、プロセス テーブル内のエントリを占有しているため、親プロセスがこの情報を読み取るまで、カーネルはプロセスの終了ステータス情報 (プロセス ID、終了ステータスなど) を保存できます。
親プロセスが子プロセスより前に終了した場合、子プロセスはプロセス 1 によってホストされます (これは、プロセスをバックグラウンドで実行させる方法でもあります)。
子プロセスが親プロセスより先に終了し、親プロセスが子プロセスの終了情報を処理しない場合、子プロセスはゾンビプロセスになります。
カーネルは、プロセス番号、終了ステータス、使用された CPU 時間などを含む、各子プロセスのデータ構造を保持します。親プロセスが子プロセスの終了情報を処理すると、カーネルはこのデータ構造を解放します。親プロセスが子プロセスの終了情報を処理しない場合、カーネルはこのデータ構造を解放せず、子プロセスのプロセス番号は常に占有されます。システム内で使用できるプロセス数には限りがあります。ゾンビプロセスが大量に生成されると、使用可能なプロセス数がなくなるため、システムは新しいプロセスを生成できなくなります。
signal(SIGCHLD, SIG_IGN)
カーネルが子プロセスの終了に関心がないことをカーネルに通知します。カーネルのデータ構造は、子プロセスが終了した直後に解放されます。wait()
/waitpid()
関数: 親プロセスは、これらの関数を呼び出して子プロセスの終了を待ち、その終了ステータスを取得することで、子プロセスが占有していたリソースを解放します。pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
pid_t wait3(int *status, int options, struct rusage *rusage);
pid_t wait4(pid_t pid, int *status, int options, struct rusage *rusage);
戻り値は子プロセスの番号です。
stat_loc
子プロセスの終了に関する情報は次のとおりです。
a) 正常に終了すると、マクロは WIFEXITED(stat_loc)
true を返す、マクロWEXITSTATUS(stat_loc)
終了ステータスを取得できます。
b) 異常終了した場合、マクロは WTERMSIG(stat_loc)
プロセスを終了するシグナルを取得します。
親プロセスがビジー状態の場合は、キャプチャできます。 SIGCHLD
Signal、信号処理関数で呼び出されますwait()
/waitpid()
。
[プロセス間でシグナルを送信する](##1.5 シグナルを送信する)
マルチプロセスサービスプログラムでは、サブプロセスが終了シグナルを受信すると、サブプロセスは単独で終了します。
親プロセスが終了シグナルを受信した場合、すべての子プロセスに終了シグナルを送信してから、親プロセス自体を終了する必要があります。
マルチスレッドはプロセスのアドレス空間を共有し、複数のスレッドが同じメモリにアクセスする必要がある場合は、グローバル変数を使用してください。。
複数のプロセスでは、各プロセスのアドレス空間は独立しており、共有されません。複数のプロセスが同じメモリにアクセスする必要がある場合、グローバル変数は使用できず、共有メモリのみが使用できます。。
共有メモリを使用すると、複数のプロセス (プロセス間の血縁関係は必要ありません) が同じメモリ空間にアクセスできます。これは、複数のプロセス間でデータを共有および転送する最も効果的な方法です。プロセスは共有メモリを自身のアドレス空間に接続できます。あるプロセスが共有メモリ内のデータを変更すると、他のプロセスによって読み取られたデータも変更されます。
共有メモリにはロック メカニズムがありません。つまり、プロセスが共有メモリを読み書きするときに、他のプロセスによる共有メモリの読み書きが妨げられません。共有メモリの読み取り/書き込みをロックしたい場合は、セマフォを使用できます。 。 Linux は、共有メモリを操作するための一連の関数を提供します。
この関数は共有メモリを作成/取得するために使用されます。
int shmget(key_t key, size_t size, int shmflg);
typedef unsigned int key_t
)、通常は 16 進数で、たとえば 0x5005
、異なる共有メモリのキーを同じにすることはできません。0666|IPC_CREAT
共有メモリが存在しない場合は作成することを示します。使使用 ipcs -m
システムの共有メモリを表示できます。これには、キー、共有メモリ ID (shmid)、所有者、アクセス許可 (perms)、およびサイズ (バイト) が含まれます。
使使用 ipcrm -m 共享内存id
共有メモリは次のように手動で削除できます。
注: コンテナーは共有メモリ内のデータ型には使用できません。使用できるのは基本データ型のみです。
この関数は、共有メモリを現在のプロセスのアドレス空間に接続するために使用されます。
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmget()
関数によって返される共有メモリ識別子。呼び出しが成功した場合は共有メモリの開始アドレスを返し、呼び出しが失敗した場合は戻ります。 (void *)-1
。
この関数は、現在のプロセスから共有メモリを切り離すために使用されます。これは以下と同等です。 shmat()
関数の逆演算。
int shmdt(const void *shmaddr);
shmat()
関数によって返されるアドレス。呼び出しが成功した場合は 0 を返し、失敗した場合は -1 を返します。
この関数は共有メモリを操作するために使用され、最も一般的に使用される操作は共有メモリの削除です。
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
関数によって返される共有メモリ ID。IPC_RMID
。呼び出しが成功した場合は 0 を返し、失敗した場合は -1 を返します。
注意、使用 root
作成された共有メモリは、作成された権限に関係なく、一般のユーザーは削除できません。
呼び出しが成功した場合は 0 を返し、失敗した場合は -1 を返します。
この関数は共有メモリを操作するために使用され、最も一般的に使用される操作は共有メモリの削除です。
int shmctl(int shmid, int command, struct shmid_ds *buf);
shmget()
関数によって返される共有メモリ ID。IPC_RMID
。呼び出しが成功した場合は 0 を返し、失敗した場合は -1 を返します。
注意、使用 root
作成された共有メモリは、作成された権限に関係なく、一般のユーザーは削除できません。
[外部リンク画像を転送中...(img-v6qW3XRA-1720711279572)]
[外部リンク画像は転送中です...(img-CG0tGAne-1720711279572)]