Linux进程线程初探(多进程与进程间通信-管道)

霸气de小男生 提交于 2019-12-09 20:50:32

先上一个多进程的简单多进程实例,此实例将在同一个程序中创建两个进程:

/*
程序说明:
创建两个进程,进程一执行”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)。

接下来就一一来探索。

管道分为无名管道和有名管道。

无名管道:

1、基于文件描述符,只能用于具有亲缘关系的进程之间的通信;

2、是一种单工的通信协议,具有固定的读断和写断;

3、无名管道不属于任何文件系统,并且只存在于内存中。

编程细解:主要使用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);
		}
}

有名管道:

1、它可以用于互不相关的两个进程间通信;

2、在文件系统中可见,但还是单工通信;

3、遵循先进先出规则。

编程细解:可以先使用 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);
}

这个程序调试需要用到两个窗口,两个程序分开编译,先打开写程序,再打开读程序。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!