1、 什麼是進程
進程是一個執行的過程
進程是一段獨立的程序,在某個數據集合上的一次運行的過程
./a.out(回車)產生了一個進程
2、進程和程序的區別和聯繫
什麼是程序----程序是寫好的代碼,是一個文件,可以保存
進程是不能保存的,程序是可以保存的
進程是動態的,程序是靜態的
程序經過編譯運行產生進程
進程是操作系統分配資源的最小單位
瞭解
init—-PID == 1
操作系統第一個進程 始祖
進程類型:
交互進程
批處理進程
守護進程
理解進程狀態
運行態 就緒態 等待態
3、理解fork
fork用來創建進程
在程序中使用fork成功後,會有父進程和子進程
可以通過fork的返回值來區分父子進程
我們不確定CPU先調度哪一個
getpid()的返回值是調用它的進程的進程號
getppid()的返回值是調用它的進程B的父進程A的進程號
結論:fork在創建子進程成功時,給父進程返回的值,是創建好的那個子進程的PID
fork給子進程返回的值是0
fork.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
//創建進程,父子進程執行相同的打印語句
int main()
{
pid_t pid = -1;
pid = fork();//create process
if (pid < 0)
{
perror("fork error");
return -1;
}
if (0 == pid)
{
sleep(10);
printf("child process, %d\r\n", getpid());
printf("%d\r\n", getppid());
}
else
{
printf("parent process, %d\r\n", pid);
printf("%d\r\n", getpid());
}
printf("after fork\r\n");
return 0;
}
4、進程的退出
1、程序運行結束 --------main中的return
2、收到信號(中斷)
3、程序中調用進程退出的函數exit,_exit
exit在進程退出時,回收資源
殭屍進程——自己寫代碼時,需要避免出現殭屍進程,父進程使用wait/waitpid可以避免產生殭屍進程
孤兒進程——父進程先結束,子進程被稱爲是孤兒進程。孤兒進程會由init進程收養
#include <stdio.h>
#include <stdlib.h>//exit
#include <unistd.h>//_exit
//exit,_exit是進程退出函數
int main()
{
int i = 3;
while (i--)
{
if (1 == i)
{
_exit(0);
}
}
printf("break from while\r\n");
return 0;
}
5、等待子進程結束
wait
waitpid
子進程在退出時調用了 exit(10)
父進程回收資源,想要獲得子進程退出狀態 wait()
pid_t wait(int * status); // 調用它時,需要傳參
pid_t waitpid(pid_t pid, int * status, int options); //一般用的比較多的是:waitpid ( pid, &status, WNOHANG);----非阻塞
得到的子進程退出狀態存放在status中,用下面的兩個宏來取出退出原因和狀態
if ( WIFEXITED ( status ) )
{
printf(“%d exit normall,status = %d\r\n”, ret, WEXTSTATUS(status));
}
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
//創建進程,父子進程執行相同的打印語句
int main()
{
pid_t pid = -1;
pid = fork();//create process
if (pid < 0)
{
perror("fork error");
return -1;
}
if (0 == pid)
{
sleep(10);
printf("child process, %d\r\n", getpid());
exit(10);
}
else
{
int status = 0;
int ret = 0;
do {
ret = waitpid(pid, &status, WNOHANG);
printf("%d\r\n", getpid());
printf("parent process, %d\r\n", pid);
sleep(1);
}while(0 == ret);
if (WIFEXITED(status))
{
printf("%d exit normall, status = %d\r\n", ret, WEXITSTATUS(status));
}
}
printf("after fork\r\n");
return 0;
}
6、exec
exec函數族提供了一種在進程中啓動另一個程序執行的方法。它可以根據指定的文件名或目錄名找到可執行文件,並用它來取代原調用進程的數據段、代碼段、和堆棧段。在執行完之後,原調用進程的內容除了進程號外,其他全部都被替換了。可執行文件既可以是二進制文件,也可以是任何Linux下可執行的腳本文件。
何時使用?
當進程認爲自己不能再爲系統和用戶做任何貢獻了就可以調用exec函數族中的函數,讓自己執行新的程序。
當前目錄: 可執行程序A B(1,2,3)
如果某個進程想同時執行另一個程序,它就可以調用fork函數創建子進程,然後在子進程中調用任何一個exec函數。這樣看起來就好像通過執行應用程序而產生了一個新進程一樣。
exec函數族使用注意點
在使用exec函數族時,一定要加上錯誤判斷語句。
因爲exec很容易執行失敗,其中最常見的原因有:
①找不到文件或路徑,此時errno被設置爲ENOENT。
②數組argv和envp忘記用NULL結束,此時errno被設置爲EFAULT。
③沒有對應可執行文件的運行權限,此時errno被設置爲EACCES。
#include <unistd.h>
int main()
{
//execlp("ls", "ls", "-l", "/home/farsight", NULL);
//execl("/bin/cat", "cat","wait2.c", NULL);
char * argv[] = {"ls", "-l", "/mnt/hgfs", NULL};
//execv("/bin/ls", argv);
//execvp("ls", argv);
char * envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
//execle("/bin/ls", "ls", "/mnt/hgfs", NULL, envp);
//execve("/bin/ls", argv, envp);
char * cmd[] = {"hello" , NULL};
execve("./hello", cmd, NULL);
return 0;
}