カーネルがCプログラムを実行するとき、カーネルはexec関数を使用して特別な起動ルーチンを呼び出し、カーネルからコマンドラインパラメータと環境変数の値を取得します。
5つの正常終了状況:
(1)从main函数返回; (2)调用exit; (3)调用_exit和_Exit函数; (4)最后一个线程调用pthread_exit; (5)最后一个线程从其启动例程返回;
3つの異常終了状況
(1)调用abort; (2)接到一个信号; (3)最后一个线程对取消请求做出响应;
プロセスは最大32個の関数(:signal関数など)を登録できます)、これらの関数は exit 関数によって自動的に呼び出されます。これらの関数は、プログラムが終了するときに呼び出され、プロセスを終了する前に仕上げ作業を実行する終了ハンドラーを形成します。 exit 関数は、atexit 関数の登録レコードを使用して、どの関数を呼び出すかを決定します。
この関数は ISO C によって定義されており、その操作には終了ハンドラーの処理とすべての標準 I/O ストリームの終了が含まれます。 ファイルディスクリプタ、マルチプロセス(親子プロセス)、ジョブ制御には対応していないことに注意してください。
プロセスがどのように終了しても、カーネル上で同じコードが実行されます (プロセスの起動と終了の図からわかるように)。このコードは、すべてのファイル記述子を閉じ、すべてのストレージ領域を解放します。
プログラムが終了したら、終了コードを使用して親プロセスにプロセスを通知します。親プロセスは、wait または waitpid 関数を使用して、子プロセスの処理を完了します (子プロセスに関する情報を取得し、子プロセスが占有しているリソースを解放します)。親プロセスが子プロセスの終了ステータスを処理しない場合、子プロセスはゾンビプロセスになります。逆に、親プロセスが子プロセスより先に終了した場合、子プロセスは孤立プロセスになります。孤立したプロセスは、プロセス番号 1 (init プロセス) によって受け取られます。一般的な処理は次のとおりです。プロセス。子プロセスの終了は非同期イベントであるため、この信号も非同期信号です。このシグナルは通常、デフォルトでは親プロセスによって無視されます。あるいは余波に対処するための信号処理機能を提供します。 wait 関数と waitpid 関数は信号処理関数の一部です。
(1)进程终止时,内核逐个检查所有活动的进程; (2)分析查找该终止进程的子进程; (3)将该进程的子进程的父进程ID改为1;ここでの呼び出し元は親プロセスを指します
環境テーブルと環境変数環境テーブルの構造図
すべてのプログラムは、環境テーブル
環境テーブルは文字ポインタの配列でもあります
enrivonは環境ポインタと呼ばれます
ポインタの配列は環境テーブルと呼ばれます
各ポインタが指す文字列は環境文字列と呼ばれます
環境変数
通常、環境変数をシェル起動ファイルに設定して、シェル
環境を変更または追加する 変数が使用される場合、変数は現在のプロセスと、生成および呼び出される後続の子プロセス (以前のプロセスには影響を与えません) の環境にのみ影響を与えますが、その環境には影響を与えません。親プロセス
環境変数に関連する関数は次のとおりです:
(1)wait会阻塞调用者进程等待直至第一个终止的子进程到来; (2)waitpid可以通过参数设置,来实现调用者进程不阻塞,或选择要阻 塞等待的子进程;
#include<stdlib.h> char *getenv(const char *name); 返回值:指向与name关联的value的指针;若未找到,返回NULL int putenv(char *str); 返回值:若成功,返回0;若出错,返回非0 int setenv(const char *name, const char *value, int rewrite); int unsetenv(const char *name); 两个函数返回值:若成功,返回0;若出错,返回-1</stdlib.h>(2) 環境テーブルを追加する
1)新value = 旧value,调用malloc函数,在堆区开辟新的存储空间,
将新value复制到这里,再将这片存储区首地址写到环境表相应的位置处。
環境変数は、現在のプログラムでは、実行時に有効です。プログラムが終了すると、対応する記憶領域がシステムによって再利用され、これらの変更は無効になります。 メモリ格納構造の補足説明
メモリ管理構造図
未初期化データセグメント(シンボルで始まるブロック): プログラムの実行開始前
、カーネルはこのセグメント内のデータを0に初期化します。または null ポインタ;スタック: 関数が呼び出されるたびに、その戻りアドレスと呼び出し元の環境情報 (一部のマシン レジスタの値など) がスタックに格納されます。
共享库:只需在所有进程都可引用的存储区中保存这种库例程的一个副本;
#include<stdlib.h> void *malloc(size_t size); void *calloc(size_t nojy, size_t size); void *realloc(void *ptr, size_t newsize); 3个函数返回值:若成功,返回非空指针;若出错,返回NULL</stdlib.h>
malloc函数:初始值不确定;底层通过调用sbrk函数实现;
calloc函数:初始值为0;
realloc函数:增加或减少以前分配区的长度;当增加长度时,可能将以前分配区的内容移到另一个足够大的区域,以便在分配区末尾增加存储区,而新增存储区初始值不确定(例如:可变数组的使用);
注意:这些动态分配的函数一般在分配存储空间时,会比要求的大。因为在开辟空间的前后部分存储记录管理信息。因此,在使用时,千万不要越界访问,以免造成不可预知的后果。
在c语言中,goto语句是不能跨函数跳转的。尤其是在函数深层调用时的跳转需求,在出错处理的情况下非常有用。
#include<setjmp.h> int setjmp(jmp_buf env); 返回值:若直接调用,返回0;若从longjmp返回,返回非0 void longjmp(jmp_buf env, int val);</setjmp.h>
变量值回滚问题:自动变量和寄存器变量会存在回滚现象。利用volatile属性来避免此类情况的发生。(在给变量赋值时,赋的值回首先存储在内存(存储器变量)中,然后在由cpu取走,存储在cpu的寄存器上(寄存器变量)。在做系统优化时,那些频繁使用的变量,会直接存储到寄存器中而不经过内存。)
在调用setjmp函数时,内核会把当前的栈顶指针保存在env变量中,所以在调用longjmp函数返回该位置时,全局变量、静态变量、易失变量和自动变量如果在调用setjmp和longjmp函数之间它们的值被修改过,是不会回滚到setjmp函数调用之前的值(当然,编译器将auto变量优化为寄存器变量除外)。因为,这些存储器变量的值是存储在内存相应的段中,回到原先栈顶状态时,同样访问的还是原先的内存空间。
然而,对于寄存器变量来说,首先要明确一点:寄存器变量是用动态存储的方式。意思是寄存器变量的值可能存在不同的寄存器中。如果在调setjmp和longjmp函数之间它们的值被修改过,这个值可能不会存到setjmp之前的对其赋值的寄存器中,而在调用longjmp函数后,又回到了调用setjmp函数时的状态。这个时候再读取寄存器变量的值时,读到的是原先那个寄存器中存储的值而不是修改过的那个寄存器中存储的值,所以出现的回滚现象。
以上がプロセス環境 - プロセス管理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。