Linux程式設計——多程序程式設計
本文學習Linux環境下的多程序程式設計,在我之前的文章裡已經講過程序與執行緒。本文,再簡單講一下程序的概念,方便接下來的學習。
程序定義:程序是一個具有一定獨立功能的程式的一次執行活動。
程序狀態圖:
當一個程序剛建立時一般處於就緒態,當就緒態的程序經過排程程式的排程將會佔有CPU,這時候就會處於執行態,程序的執行過程中進行I/O操作,想要從裝置讀取資料,而此時又無資料可讀,這是程序有執行態轉換為阻塞態,當有資料來之後,I/O操作完成,程序又由阻塞態轉變為就緒態。
程序 ID
程序 ID(PID):標識程序的唯一數字
父程序的 ID(PPID)
啟動程序的使用者 ID(UID)
程序互斥
程序互斥是指當有若干程序都要使用某一共享資源時,任何時刻最多允許一個程序使用,其他要使用該資源的程序必須等待,直到佔有該資源者釋放了該資源為止。
臨界資源
作業系統中將一次只允許一個程序訪問的資源稱為臨界資源。
臨界區
程序中訪問臨界資源的那段程式程式碼稱為臨界區。為實現對臨界資源的互斥訪問,應保證諸程序互斥地進入進入各自的臨界區。
程序同步
一組併發程序按一定的順序執行的過程稱為程序間的同步。具有同步關係的一組併發程序稱為合作程序,合作程序間互相傳送的訊號稱為訊息或事件。
程序排程
概念:按一定演算法,從一組待執行的程序中選出一個來佔有CPU執行時間。
排程方式:搶佔式和非搶佔式。
排程演算法:先來先服務排程演算法,短程序優先排程演算法,高優先順序優先排程演算法,時間片輪轉演算法。
獲取程序 ID
獲取本程序 ID:pid_t getpid(void)
獲取父程序 ID:pid_t getppid(void)
示例程式碼:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("PID=%d\n",getpid());
printf("PPID=%d\n",getppid());
return 0;
}
程序建立—fork
需要包含標頭檔案:#include<unistd.h>
函式呼叫:pid_t fork(void)
函式功能:建立子程序。fork 被呼叫一次,返回兩次,它可能有三種不同的返回值:1.在父程序中,fork 返回新建立的子程序的 PID;2.在子程序中,fork 返回0;3.如果出現錯誤,fork 返回一個負值。
示例程式碼:
int main()
{
pid_t child;
/* 建立子程序 */
if((child=fork())==-1)
{
printf("Fork Error : %s\n", strerror(errno));
exit(1);
}
else
{
if(child==0) // 子程序
{
printf("I am the child: %d\n", getpid());
exit(0);
}
else //父程序
{
printf("I am the father:%d\n",getpid());
return 0;
}
}
}
程序建立—vfork
需要包含標頭檔案:#include<sys/types.h>,#include<unistd.h>
函式呼叫:pid_t vfork(void)
函式功能:建立子程序
示例程式碼:
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
int main(void)
{
pid_t child;
/* 建立子程序 */
if((child=vfork())==-1)
{
printf("Fork Error : %s\n", strerror(errno));
exit(1);
}
else
{
if(child==0) // 子程序
{
sleep(1); //子程序睡眠一秒
printf("I am the child: %d\n", getpid());
exit(0);
}
else //父程序
{
printf("I am the father:%d\n",getpid());
exit(0);
}
}
}
fork 和 vfork 的區別
fork:子程序拷貝父程序的資料段,且父、子程序的執行次序不確定
vfork:子程序與父程序共享資料段,子程序先執行,父程序後執行
exec 函式族
exec 用被執行的程式替換呼叫它的程式。也就是說 exec 啟動一個新程式,替換原有的程序,因此程序的 PID 不會改變。
需要包含標頭檔案:#include<unistd.h>
函式呼叫:int execl(const char *path,const char *arg1,...)
引數:path:被執行程式名(含完整路徑);arg1-argn:被執行程式所需的命令列引數,含程式名。以空指標(NULL)結束
示例程式碼:使用 execl 函式在程式內部呼叫可執行程式建立一個檔案。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
/*判斷入參有沒有傳入檔名*/
if(argc<2)
{
perror("you haven,t input the filename,please try again!\n");
exit(EXIT_FAILURE);
}
/*呼叫execl函式,用可執行程式file_creat替換本程序*/
if(execl("./file_creat","file_creat",argv[1],NULL)<0)
perror("execl error!");
}
函式呼叫:int execv(const char *path,const char *argv[ ])
引數:path:被執行程式名(含完整路徑)。argv[ ]:被執行程式所需的命令列引數陣列。
示例程式碼:
#include<unistd.h>
int main()
{
char *argv[]={"ls","-al","/etc/passwd",(char *)0};
execv("/bin/ls",argv);
return 0;
}
程序等待
需要包含標頭檔案:#include<sys/types.h>,#include<sys/wait.h>
函式呼叫:pid_t wait(int *status)
功能:阻塞該程序,直到某個子程序退出。
示例程式碼:
int main(void)
{
pid_t child;
/* 建立子程序 */
if((child=fork())==-1)
{
printf("Fork Error : %s\n", strerror(errno));
exit(1);
}
else
{
if(child==0) // 子程序
{
printf("the child process is run\n");
sleep(1); //子程序睡眠一秒,但並沒有去執行父程序
printf("I am the child: %d\n", getpid());
exit(0);
}
else //父程序
{
wait(NULL); //等到子程序退出,父程序才會執行
printf("the father process is run\n");
printf("I am the father:%d\n",getpid());
return 0;
}
}
}