fork

获取当前进程的PID和父进程的PID。
创建getpid1.c,编辑如下内容
在这里插入图片描述
执行过程:
在这里插入图片描述
在当前系统中使用ps和grep查找父进程2330,可以看到,id为2330的进程为bash即当前的脚本程序,因为是在当前bash中运行此程序,所以父进程为bash
在这里插入图片描述
进程创建fork()
产生进程的方式比较多,fork()是其中的一种方式。fork()函数以父进程为蓝本复制一个进程,其ID号和父进程ID号不同在Linux环境下,fork()是以写复制实现的。只有内存等与父进程不同,其他与父进程共享,只有在父进程或者子进程进行了修改后,才重新生成一份。
原理:
fork()执行一次,返回两次。在父进程和子进程中返回的是不同的值,父进程返回的是子进程的ID号,而子进程中则返回0,如果出错,fork()返回1.
在这里插入图片描述
fork函数创建一个新的进程,并从内核中为此进程得到一个新的可用进程ID,之后为这个新进程分配进程空间,并将父进程的进程空间中的内容复制到子进程的进程空间中,包括父进程的数据段+堆栈段,并与父进程共享代码段。
fork函数之后,子进程从等待fork返回开始执行,而不是从头开始。
注意:子进程完全复制了父进程的地址空间的内容,包括堆栈段+数据段的内容。但是,**子进程并没有复制代码段,而是和父进程共享代码段。**代码段是只读的,不存在修改的问题,因此可以共用。在创建一个子进程后,子进程的地址空间完全和父进程分开,父子进程是两个独立的进程。
例题1.
fork1.c


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


int main()
{

    int n = 10;

    //进程复制
    int pid = fork();

    //fork失败
    if(-1 == pid)
    {
        perror("fork");
        exit(-1);
    }

    if(0 == pid)
    {//子进程

        printf("child pid=%d,ppid=%d\n",getpid(),getppid());
        printf("&n=0x%x\n",&n);

        exit(0);
    }
    else if(pid > 0)
    {//父进程

       //让当前进程休眠1秒
       //sleep(1);
    
       //等待进程结束
       //wait(NULL);


        printf("father pid=%d,ppid=%d\n",getpid(),getppid());
        printf("&n=0x%x\n",&n);

        
      //  wait(NULL);
    
    }

    return 0;
}

在这里插入图片描述

注意:当在父进程前加sleep(1)当前程序等待1秒让子进程先结束,不让子进程成为孤儿,也可输入wait(NULL)等待进程结束
在这里插入图片描述
当在父进程前后加wait(NULL)
在这里插入图片描述

例题2

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


int main()
{
    int n = 1;
    //如果fork成功,则返回两次
    pid_t pid = fork();
    if(-1 == pid)
    {
        perror("fork:");
        exit(-1);
    }
    if(pid == 0)
    {//子进程  
        while(1)
        {
            n++;    
            printf("child pid=%d,ppid=%d\n",getpid(),getppid());
            sleep(1);
        }
        exit(0);
    }
    else
    {//父进程
        while(1)
        {
            printf("father pid=%d,n=%d\n",getpid(),n);

            sleep(1);
        }
    }
    printf("main ending!\n");
    return 0;
}

执行过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
子进程会拷贝父进程的所有资源,变量。
注意:子进程拷贝了父进程数据空间、堆、栈等资源的副本,
父子进程间不共享这些存储空间,共享的空间只有代码段,
子进程修改一个全局变量,父进程的这个全局变量不会改变,因为是一个副本。

强制结束父进程,则1号接管子进程
在这里插入图片描述
注意结束进程执行过程如下:
在这里插入图片描述
fork3.c

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

/*全局变量*/
char *msg = "shenlan";
int g_value = 0;

int main()
{
	printf("%s\n", msg);

	int val = 0;

	printf("uid:%d,euid:%d,gid:%d,egid:%d\n", getuid(), geteuid(), getgid(), getegid());

	pid_t id = fork();

	if (id < 0)
	{
		printf("fork error\n");
		exit(1);
	}
	else if (id == 0)
	{//子进程执行代码
		val++;
		g_value++;

		printf("child:pid:%d,ppid:%d,val:%d,&val:0x%x,g_value:%d,&g_value:0x%x\n",
			getpid(), getppid(), val, &val, g_value, &g_value);

	}
	else
	{//父进程执行代码

		sleep(1);

		printf("father:pid:%d,ppid:%d,val:%d,&val:0x%x,g_value:%d,&g_value:0x%x\n",
			getpid(), getppid(), val, &val, g_value, &g_value);

		sleep(3);

	}

	return 0;

}

执行过程:
在这里插入图片描述

filed1.c

/*
父子进程的文件描述符可以共享,但是要在fork之前打开,并在公有代码中关闭文件
*/

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *args[])
{
	// 打开文件描述符:在fork之前打开才能让父进程和子进程共享
	int fd = open("data.txt", O_RDONLY);

	// 判断文件打开是否成功
	if (fd == -1)
	{
		printf("File open failed : %s\n", strerror(errno));
	}

	// 定义读取文件的缓冲区
	char buf[1024];

	//读取到的字节数
	int nread;


	// 执行fork函数
	pid_t pd = fork();
	// 判断fork是否成功
	if (pd == -1)
	{
		printf("fork failed : %s\n", strerror(errno));
	}

	// 通过if...else...执行父子进程的特有代码
	if (pd > 0)
	{
		sleep(5);

		//清空缓冲区内存
		memset(buf, 0, sizeof(buf));
		// 读取文件内容
		nread = read(fd, buf, 7);

		buf[nread] = '\0';
		//将读取到的内容显示到屏幕上
		printf("%s\n", buf);


		printf("father fd = %d\n", fd);

		//关闭文件描述符
		close(fd);
	}
	else
	{
		//清空缓冲区内存
		memset(buf, 0, sizeof(buf));
		// 读取文件内容
		nread = read(fd, buf, 5);

		buf[nread] = '\0';
		//将读取到的内容显示到屏幕上
		printf("%s\n", buf);

		printf("son fd = %d\n", fd);

		//关闭文件描述符
		close(fd);
	}

	printf("process [%d] ending!\n", getpid());

	return 0;
}

执行过程:

在这里插入图片描述
problem1.c

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

int main(void)  
{  
	int i;  
	for(i=0; i<2; i++){  
		fork();  
		printf("-");  
	}
	return 0;  
} 

在这里插入图片描述
vfork1.c

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

/*全局变量*/
int g_value = 0;

int main()
{

	int val = 0;

	printf("uid:%d,euid:%d,gid:%d,egid:%d\n", getuid(), geteuid(), getgid(), getegid());

	pid_t id = vfork();

	if (id == -1)
	{
		printf("fork error\n");
		exit(1);
	}


    if (id == 0)
	{//子进程执行代码
		val++;
		g_value++;

		printf("child:pid:%d,ppid:%d,val:%d,&val:0x%x,g_value:%d,&g_value:0x%x\n",
			getpid(), getppid(), val, &val, g_value, &g_value);

        exit(0);

	}
	else if(id > 0)
	{//父进程执行代码

		sleep(2);

		printf("father:pid:%d,ppid:%d,val:%d,&val:0x%x,g_value:%d,&g_value:0x%x\n",
			getpid(), getppid(), val, &val, g_value, &g_value);


	}

	return 0;

}

执行过程:
在这里插入图片描述
wait1.c

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


int main()
{

    int n = 10;

    int pid = fork();

    if(-1 == pid)
    {
        perror("fork");
        exit -1;
    }

    if(0 == pid)
    {
        printf("child pid=%d,ppid=%d\n",getpid(),getppid());

        sleep(1);

        exit(1);
    }
    else if(pid > 0)
    {
        printf("father pid=%d,ppid=%d\n",getpid(),getppid());

        int status;

        //阻塞当前进程,等待子进程推出
        //pid_t pid = wait(&status);
        //pid_t pid = waitpid(-1,&status,0);

        //WNOHANG,代表非阻塞
        pid_t pid = waitpid(-1,&status,WNOHANG);

        printf("child process id = %d\n",pid);

        //如果子进程返回值不为0(exit 0)
        if(WIFEXITED(status))
        {
            printf("child process status = %d\n",WEXITSTATUS(status));
        }
    
    }

    return 0;
}

执行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值