linux下的多进程学习探究

入门

1. 要点

1.进程相当于自我复制,将自己复制到另一个内存区域执行。复制出来的进程叫做子进程,进程之间相互独立(全局变量也是独立拥有的)。

2.Fork创建的新进程是和父进程(除了PID和PPID)一样的副本,包括真实和有效的UID和GID、进程组合会话ID、环境、资源限制、打开的文件以及共享内存段。

3.如果fork执行成功,就向父进程返回子进程的PID,并向子进程返回0。这就一起这即使你只调用fork一次,他也会返回两次。

4.子进程与父进程没有绝对的先后执行顺序。

5.子进程死后就会变成僵尸进程,需要父进程处理尸体(waitpid)。否则子进程要等到父进程结束才会退还资源。

2. 相关函数

创建一个子进程

  • pid_t fork(void)

头文件 #include<unistd.h>
返回值:

向父进程返回子进程的PID,并向子进程返回0。错误返回-1。

示例:

pid_t PID;
PID = fork();

执行进程

  • exec族

int execl(const char path, const chararg, ...) //execl没有继承环境变量
int execlp(const char path, const chararg, ...) //execlp继承了环境变量

头文件 #include<unistd.h>
const char *path:

要执行的二进制文件或脚本的路径(绝对路径,相对路径都可以)

const char *arg :

是要传递给程序的完整参数

返回值:

失败返回-1,成功就跳转到新进程了。

示例:

execl("/bin/ls", "-a","/etc/passwd",(char*)0);
execl("ls","-a","/etc/passwd",(char*)0);

清理子进程尸体

  • 非阻塞:pid_t waitpid(pid_t pid,int * status,int options)

头文件 #include<sys/wait.h>
pid:

pid>0,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0:等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1:等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

status:

传递出进程结束时的状态。不在意可使用NULL

返回值:

函数若成功,返回进程PID,若出错则返回-1;

  • 阻塞:pid_t wait(int * status)

头文件 #include<sys/wait.h>
status:

传递出进程结束时的状态。不在意可使用NULL

返回值:

函数若成功,返回进程PID,若出错则返回-1;

获取PID

  • 获取自身pid:pid_t getpid()

头文件 #include<unistd.h>
返回值:

函数若成功,返回自身进程PID,若出错则返回-1;

  • 获取父进程pid:pid_t getppid()

头文件 #include<unistd.h>
返回值:

函数若成功,返回父进程PID,若出错则返回-1;

代码示例

  • mult_pid.c
#include<unistd.h>  
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  

int main(void)  
{  
    pid_t pid;  

	pid = fork();  

	if(pid > 0)   //父进程   
	{   
		printf("\n in parent \n");   
		printf("tparent pid = %d\n",getpid());  	
		printf("tparent ppid = %d\n",getppid());  	
		wait(NULL);
	}  
    else if(pid == 0) //子进程中  
	{  
		printf("\n in child \n");   
		printf("tchild pid = %d\n",getpid());  	
		printf("tchild ppid = %d\n",getppid());  	
		if(execl("ls", "-a",(char*)0) < 0)
		{
			perror("execl");  
			exit(1);  
		}
	}  
    else   
	{  
		perror("fork");  
		exit(1);  
	}  
	
}  	

进阶

1. 进程间通信

说明

为什么进程需要额外的通信手段呢?

因为进程的创建时,从父进程克隆所有资源后就相对独立了。所有的资源都是独立开来的,不会影响到父进程的资源。因此需要通信机制来使得进程间协同工作,例如:进程同步,数据传输等等。

线程?进程?

这里我就喜欢比较线程了,线程虽然也是克隆而来,有自己的资源,但相对没有那么独立,比如全局变量还是同一个。独立的只有局部变量。这和单片机的结构非常相似。

通信机制

2. 进程的探索

代码

  • ./main.c
#include<unistd.h>  
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
#include<sys/types.h>
#include<sys/wait.h>

int main(void)  
{  
    pid_t pid;  

	pid = fork();  
    
	if(pid > 0)   //父进程   
	{     
        printf("in main\n"); 
        wait(NULL); //主进程程序会一直卡在这,直到子进程结束

        printf("hello\n"); 
        if(execlp("pwd", "",(char*)0) < 0)
        {   
            perror("execl");   
            exit(1);  
        }    
 		//后面所有的代码不会再执行
	}  
    else if(pid == 0) //子进程中  
	{   
		printf("in main child \n");   

        if(execlp("./bin/bin", "",(char*)0) < 0) //这个相对路径是shell当前路径
        {   
            perror("execl");  
            exit(2);  
        } 
		//后面所有的代码不会再执行
	}   
    else   
	{  
		perror("fork");  
		exit(1);  
	}  
	
}  	
  • ./bin/bin.c
#include<unistd.h>  
#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  

int main(void)  
{   
    sleep(3);
	printf("\nin bin\n");    
    if(execlp("pwd", "",(char*)0) < 0) //跳转到系统进程pwd
    {    
        perror("execl");  
        exit(1);  
    }  
	//后面所有的代码不会再执行 
}  	

结论

相对路径?

这个相对路径是shell当前路径,而不是主进程的所在路径。

exec簇执行,新进程执行?直接跳转到目标进程?

跳转到目标进程。也就是说,相当于将该fork出来的进程转变成了目标进程。就算目标进程结束也不会再回来。

posted @ 2018-01-15 20:43  WittXie  阅读(299)  评论(0编辑  收藏  举报