Linux進程線程初探(多進程與進程間通訊-管道)

先上一個多進程的簡單多進程實例,此實例將在同一個程序中建立兩個進程:編程

/*
程序說明:
建立兩個進程,進程一執行」ls -l「操做,進程二作sleep操做
主進程阻塞等待進程1結束,再等待進程2結束,程序結束
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
	pid_t child1,child2;
	child1 = fork();		//進程1
	if(child1 == -1){
		perror("child1 creat error:");
		exit(1);
	}else
	if(child1 == 0){
		if(execlp("ls","ls","-l",NULL) < 0){
			perror("execlp error:");
			exit(1);
		}
		exit(0);
	}
	child2 = fork();		//進程2
	if(child2 == -1){
		perror("child2 creat error:");
		exit(1);
	}else
	if(child2 == 0){
		sleep(3);
		exit(0);
	}
	
	// waitpid(child1,NULL,0);		主進程
	wait(0);
	while(waitpid(child2,NULL,WNOHANG)==0){
		printf("child2 not exit\n");
		sleep(1);
	}
	exit(0);
}

建立多進程的時候須要注意,不要連續建立多個進程,不然上面建立的子進程將同時建立下面的進程,向下面這樣:數組

child1 = fork();
child2 = fork();

經過下面代碼能夠看出子進程1同時也建立了進程2:安全

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
	pid_t child1,child2,child_temp;
	child1 = fork();
	child2 = fork();
	if(child1 == -1){
		perror("child1 creat error:");
		exit(1);
	}
	if(child2 == -1){
		perror("child2 creat error:");
		exit(1);
	}
	if(child1 == 0){
		sleep(2);
		// exit(0);
		wait(0);
	}
	if(child2 == 0){
		sleep(3);
		exit(0);
	}
	// waitpid(child1,NULL,0);
	while(waitpid(child1,NULL,WNOHANG)==0){
		printf("chil1 has not exit\n");
		sleep(1);
	}
	while(waitpid(child2,NULL,WNOHANG)==0){
		printf("child2 has not exit\n");
		sleep(1);
	}
	exit(0);
}

 

不少時候,不一樣的進程之間須要交換數據,即相互通訊。而進程之間的通行方式也有多種,爲了知足進程間通訊在不一樣場景下的需求:管道通訊(pipe),信號(signal),信號量(semaphore),共享內存(shared memory),消息隊列(message queue),套接字(socket)。socket

接下來就一一來探索。函數

管道分爲無名管道和有名管道。翻譯

無名管道:調試

一、基於文件描述符,只能用於具備親緣關係的進程之間的通訊;code

二、是一種單工的通訊協議,具備固定的讀斷和寫斷;索引

三、無名管道不屬於任何文件系統,而且只存在於內存中。隊列

編程細解:主要使用pipe()函數,例程爲一個父進程寫進,子進程讀取的一個進程間通訊實例。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>

#define MaxDataLen 256
#define DelayUTime 1

int main()
{
	pid_t pid;
	int pipe_fd[2];
	char buf[MaxDataLen];
	const char data[] = "Pipe Test Program";
	int real_read,real_write;
	
	memset(buf,0,sizeof(buf));
	if(pipe(pipe_fd)<0)	
	/*
	pipe運行機制:
	函數原型:int pipe(int pipefd[2]);
	描述:pipe()用於建立一個單向數據通道,能夠用於進程間通訊;
	使用數組pipefd返回兩個文件描述符指管的兩端;
	pipefd[0]是指讀的管道。pipefd[1]是指寫的管道;
	數據在已寫入管道而未被讀取時由內核提供緩衝。	
	*/
	{
		perror("creat pipe failed:");
		/*
		perror運行機制:
		函數原型:void perror(const char *S);
		描述:當一個系統調用失敗時,它一般會返回-1並設置變量errno用於描述這個錯誤(這個值能夠在errno.h中找到)\
		perror函數會翻譯這些值成爲可閱讀的信息。errno會在一個成功的系統調用會是庫函數調用後變成undefined。
		程序中存在一個全局的錯誤表sys_errlist[],能夠被下標errno索引。
		NOTES: sys_nerr & sys_errlist 在 <stdio.h> 中
		SEE ALSO: err(),errno(),error(),strerror()
		*/
		exit(-1);
	}
	if((pid = fork()) == 0){	//子進程爲讀端
		close(pipe_fd[1]);
		usleep(DelayUTime);
		if((real_read = read(pipe_fd[0],buf,MaxDataLen)) > 0){
			printf("%d bytes:%s\n",real_read,buf);
		}
		close(pipe_fd[0]);
		exit(0);
	}else
		if(pid > 0){			//父進程爲寫端
			close(pipe_fd[0]);
			if((real_write = write(pipe_fd[1],data,strlen(data))) != -1){
				printf("wrote %d bytes:'%s'\n",real_write,data);
			}
			close(pipe_fd[1]);
			wait(0);
			exit(0);
		}
}

有名管道:

一、它能夠用於互不相關的兩個進程間通訊;

二、在文件系統中可見,但仍是單工通訊;

三、遵循先進先出規則。

編程細解:能夠先使用 mkfifo 指令在磁盤中建立一個有名管道文件,而後再程序中打開;也能夠在程序中使用mkfifo()函數建立有名管道。讀寫依舊使用read(),write()函數。

mkfifo Linux指令:
mkfifo [OPTION]... NAME...
描述:建立名爲NAME的fifo文件;
options:
-m, --mode=MODE
       設置文件權限位模式
-Z     設置SELinux安全上下文的默認類型

例:mkfifo -m 777 /tmp/temp

對於有名管道,咱們使用一個寫端程序和一個讀端程序來看進程通訊:

/*
fifo_write.c
寫端程序
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
	int fifo_fd;
	char buf[] = "hello";
	if((fifo_fd = open("/tmp/temp",O_WRONLY,0600)) < 0){
		fifo_fd = mkfifo("/tmp/temp",0777);		//如沒有此管道文件,mkfifo()建立管道文件
	}
	if(write(fifo_fd,buf,strlen(buf)) > 0){
		printf("Write '%s' to FIFO\n",buf);
	}
	close(fifo_fd);
	exit(1);
}
/*
fifo_read.c
讀端程序
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
	int fifo_fd;
	char buf[256];
	fifo_fd = open("/tmp/temp",O_RDONLY);
	if(fifo_fd < 0){
		perror("open temp failed:");
		exit(-1);
	}
	while(1){
		memset(buf,0,sizeof(buf));
		if(read(fifo_fd,buf,256) > 0){
			printf("Read '%s' from FIFO\n",buf);
		}
	}
	close(fifo_fd);
	exit(1);
}

這個程序調試須要用到兩個窗口,兩個程序分開編譯,先打開寫程序,再打開讀程序。

相關文章
相關標籤/搜索