1. 程式人生 > >Linux程式設計——多程序程式設計

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;
		}
	}
}