日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 进程

發布時間:2023/12/31 linux 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 进程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Linux 進程

  在用戶空間,進程是由進程標識符(PID)表示的。從用戶的角度來看,一個 PID 是一個數字值,可惟一標識一個進程。一個 PID 在進程的整個生命期間不會更改,但 PID 可以在進程銷毀后被重新使用,所以對它們進行緩存并不見得總是理想的。

進程表示

  在 Linux 內核內,進程是由相當大的一個稱為?task_struct?的結構表示的。此結構包含所有表示此進程所必需的數據,此外,還包含了大量的其他數據用來統計(accounting)和維護與其他進程的關系(父和子)。

struct task_struct {volatile long state;void *stack;unsigned int flags;int prio, static_prio;struct list_head tasks;struct mm_struct *mm, *active_mm;pid_t pid;pid_t tgid;struct task_struct *real_parent;char comm[TASK_COMM_LEN];struct thread_struct thread;struct files_struct *files;...}; View Code

進程管理

  在很多情況下,進程都是動態創建并由一個動態分配的?task_struct?表示。一個例外是init?進程本身,它總是存在并由一個靜態分配的?task_struct?表示。

  在 Linux 內雖然進程都是動態分配的,但還是需要考慮最大進程數。在內核內最大進程數是由一個稱為max_threads?的符號表示的,它可以在 ./linux/kernel/fork.c 內找到。可以通過 /proc/sys/kernel/threads-max 的 proc 文件系統從用戶空間更改此值。

  Linux進程分為兩種基本類型,分別為內核進程用戶進程。內核進程通過內核中kernel_thread()函數創建的,用戶進程通過fork()和clone()創建。

進程的創建&內存的復制

  創建一個子進程,就創建了一個新的子任務,并為它復制了父進程的內存。但是這兩個進程使用的內存是相互獨立的。在調用fork函數的時候,父進程當時的所有變量對子進程都是可見的,fork函數執行完成之后,父進程的變量對于子進程來說就隱藏了。

  在創建一個新進程時,父進程使用的內存并不是真正的全部復制給子進程。它們都指向同一處內存空間,但是把內存頁面標記為copy-on-write。當任何一個進程試圖向這些內存中寫入內容時,就會產生一組新的內存頁面由這個進程私有。這樣,通過這種方法提高了創建新進程的效率,因為內存空間的復制推遲到了發生寫操作的時候。

進程相關API

  Linux下進程模型提供了很多API函數,下面的這些函數可以完成基本的工作。

API函數用途
fork創建子進程
wait將進程掛起,直到子進程退出
waitpid ? ? ?將進程掛起,直到指定子進程退出
signal注冊新的信號
pause 將進程掛起,直到捕捉到信號
kill向某個指定的進程發出信號
raise向當前進程發出信號
exec將當前進程映像用一個新的進程映像來替換
exit正常終止當前進程

函數詳解&具體應用

  日常編程中,我們常用到多進程的方式,可以讓我們的程序同步執行多個任務。接下來,從函數原型依次介紹并用實例來分析。

進程的創建fork

  API函數fork用于在一個已經存在的父進程中創建一個新的進程,子進程除了ID與父進程不同,其余都相同。

pid_t fork( void ); //pid_t是進程描述符 //返回值:>0, 當前進程就是父進程;==0,當前進程就是子進程;<0,失敗
//返回值<0時,有兩種錯誤,都是內存不足問題,分別為EAGAIN/ENOMEM
1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 5 int main() 6 { 7 pid_t pid; 8 9 pid = fork(); 10 if(pid > 0) 11 printf("Parent process pid: %d\n",getpid()); 12 else if(pid == 0) 13 printf("Child process pid: %d\n",getpid()); 14 else 15 printf("fork error!\n"); 16 17 return 0; 18 } View Code

進程關閉exit

  API函數exit終止調用進程,傳入exit的參數會返回給父進程。

  子進程調用exit函數還會向父進程發出SIGCHLD信號,釋放當前進程的資源。

//關閉進程 void exit( int status );
//status用來保存狀態信息

信號signal

  signal_handler函數允許用戶為進程注冊信號句柄。在信號被注冊后,就可以在需要的時候調用信號API函數。

  PS: 在做一個WIN32控制臺下的程序時候需要動態控制,我就利用SIGINT信號,在程序運行的過程中使用CTRL+C,調用中斷函數完成操作。

//信號句柄 void signal_handler( int signal_number );//注冊信號 sighandler_t signal( int signum, sighandler_t handler ); //signum為信號類型 //handler為與信號相關聯的動作

//sighandler_t的類型定義:typedef void (*sighandler_t)(int) *****指向函數的指針******

  進程的信號句柄分為三種類型,分別為忽略類型、默認指定類型和用戶自定義句柄類型。

  例子:

1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <signal.h> 5 6 void catch_signal_ctrl_c(int sig_num) 7 { 8 printf("catch signal ctrl+n"); 9 fflush(stdout); 10 } 11 12 int main() 13 { 14 signal(SIGINT, catch_signal_ctrl_c); //注冊信號SIGINT軟件中斷,通過輸入ctrl+c可以發出 15 16 printf("run a pause"); 17 pause(); //進程掛起,等待信號 18 19 return 0; 20 } View Code

進程掛起pause

  函數pause會把進程掛起,直到接收到信號。在信號接收后,進程會從pause函數中退出,繼續運行。?

//掛起 int pause( void );

向當前進程發送信號raise

  raise函數只可以向當前進程發出信號。

int raise( int sig_num );

  例子:

1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <signal.h> 5 6 void catch_signal_ctrl_c(int sig_num) 7 { 8 printf("catch signal ctrl+n"); 9 fflush(stdout); 10 } 11 12 int main() 13 { 14 signal(SIGINT, catch_signal_ctrl_c); //注冊信號SIGINT軟件中斷,通過輸入ctrl+c可以發出 15 16 raise(SIGINT); 17 18 return 0; 19 } View Code

向其他進程發送信號kill

  kill函數可以向一個進程或一系列進程發送信號。

int kill( pid_t pid, int sig_num );

  參數pid的不同會有不同的效果:

pid說明
>0 ??發送信號到pid指定進程
0發送信號到與本進程同組的所有進程
-1發送信號到所有進程(init進程除外)
<0發送信號到由pid絕對值指定的進程組中的所有進程?

?

進程掛起wait&waitpid

  wait函數與waitpid函數都是將進程掛起,直到某個進程退出或信號發生,避免僵尸進程的產生。

  子進程退出,父進程沒有等待(調用wait / waitpid)它, 那么她將變成一個僵尸進程。 但是如果該進程的父進程已經先結束了,那么該進程就不會變成僵尸進程, 因為每個進程結束的時候,系統都會掃描當前系統中所運行的所有進程, 看有沒有哪個進程是剛剛結束的這個進程的子進程,如果是的話,就由Init 來接管它,成為它的父進程

  wait只根據任何一個子進程退出狀態。

pid_t wait( int *status ); //返回退出子進程的pid值,如果為-1,發生錯誤 //status用來保存子進程退出的狀態信息

  通過評估函數可以知道子進程退出的狀態信息。

說明
WIFEXITED如果子進程正常退出,則不為0 ?
WEXITSTATUS ??返回子進程的exit狀態
WIFSIGNALED如果子進程因為信號退出,則為ture
WTERMSIG返回引起子進程退出的信號號(僅在WIFSIGNALED為ture的時候)

  例子:

1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <signal.h> 5 6 int main() 7 { 8 pid_t pid; 9 int status; 10 11 pid = fork(); 12 if(pid > 0){ 13 printf("Parent process, pid: %d\n", getpid()); 14 15 printf("父進程掛起!\n"); 16 pid = wait(&status); 17 18 printf("父進程恢復\n"); 19 20 }else if(pid == 0){ 21 22 printf("Child process, pid: %d\n", getpid()); 23 printf("子進程退出\n"); 24 exit(status); 25 26 }else{ 27 printf("fork error\n"); 28 } 29 30 return 0; 31 } View Code

  waitpid是掛起父進程直到某個指定的子進程退出。

pid_t waitpid( pid_t pid, int *status, int options); //pid用來指定進程 //status保存退出進程狀態 //options有兩種選擇,WNOHANG/WUNTRACED/* WNOHANG:設定在子進程未退出時也不掛起調用進程,但僅在子進程退出時返回 WUNTRACED:返回已經停止而且自停止之后還未報告狀態的子進程 */

  pid的取值:

pid說明
>0 ? ? ? ?掛起直到由pid指定的子進程退出?
0掛起直到任何一個與調用進程的組ID相同的子進程退出 ?
-1掛起直到任何子進程退出,與wait相同
<-1掛起直到任何一個其組ID與pid參數的絕對值相同的子進程退出 ?

  waitpid增加兩個宏:

    WIFSTOPPED: 如果子進程現在已經停止,返回true

    WSTOPSIG:  返回使子進程停止的信號(WIFSTOPPED為true) 

發送警告信號alarm

  alarm函數在其他函數超時的時候會發送一個SIGALRM信號。

unsigned it alarm( unsigned int secs ); //secs為時間,單位為秒 //如果在超時,未接收到警告信號,返回0,否則,返回等待警告信號的時間

?  例子:

1 #include <stdio.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <signal.h> 5 #include <string.h> 6 7 void wakeup(int sig_num) 8 { 9 print("timeout quit"); 10 raise(SIGINT);//產生中斷信號 11 } 12 13 int main() 14 { 15 int ret; 16 char buffer[1024]; 17 18 signal(SIGALRM, wakeup); 19 20 printf("timeout in 3 seconds, please enter your password\n"); 21 alarm(3); 22 23 ret = read(0, buffer, 1023); 24 if(ret >= 0){ 25 buffer[strlen(buffer)-1]='\0'; 26 printf("password : %s", buffer); 27 } 28 29 return 0; 30 } View Code

替換當前進程exec

  exec函數用于完全替換當前進程映像。實際上,就是用一個新的程序來替換當前的進程。值得注意的是,如果替換了,就不可能恢復,是完全的替換。

int execl( const char *path, const char *arg, ... ) //path確定要運行的程序 //其他都為參數/* 例子:execl( "/bin/ls", "ls", "-la", NULL );//用ls命令程序來替換當前進程 */

  例子:

1 #include <stdio.h> 2 #include <unistd.h> 3 #include <stdlib.h> 4 #include <sys/types.h> 5 #include <signal.h> 6 #include <string.h> 7 8 9 int main() 10 { 11 int status; 12 char cmd[100]; 13 char* ret; 14 pid_t pid; 15 16 while(1){ 17 printf("mysh>>"); 18 ret = fgets(cmd, sizeof(cmd), stdin); 19 if(ret == NULL) 20 exit(-1); 21 cmd[strlen(cmd)-1]='\0'; 22 23 if(!strncmp(cmd, "quit", 4)) 24 exit(0); 25 26 pid = fork(); 27 if(pid == 0){ 28 execlp(cmd, cmd, NULL); 29 }else if(pid >0){ 30 waitpid(pid, &status, 0); 31 } 32 printf("\n"); 33 } 34 } View Code

參考

GNU/LINUX環境編程

http://www.cnblogs.com/avril/archive/2010/03/22/1691793.html

http://www.ibm.com/developerworks/cn/linux/l-linux-process-management/


本作品由cococo點點創作,采用知識共享署名-非商業性使用-相同方式共享 3.0 中國大陸許可協議進行許可。歡迎轉載,請注明出處:
轉載自:cococo點點 http://www.cnblogs.com/coder2012

轉載于:https://www.cnblogs.com/coder2012/p/3176760.html

總結

以上是生活随笔為你收集整理的Linux 进程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。