008进程及fork创建进程_LINUX

本文介绍了Linux中的进程概念,强调进程是运行的程序,解释了并发执行的原理,包括单道和多道程序设计。详细讨论了MMU在虚拟内存管理中的作用,PCB(进程控制块)的构成,以及fork函数如何创建子进程。文章还提供了示例代码展示如何创建并调试子进程,探讨了父子进程的异同,强调了它们在数据共享上的特点。
摘要由CSDN通过智能技术生成

进程及fork创建子进程

1. 进程概念

程序:只占用磁盘空间,死的
进程:运行起来的程序。占用内存、cpu等系统资源,是活的程序

2. 并发概念

并发,在操作系统中,一个时间段中有多个进程都处于启动运行到运行完毕之间的状态,但,任一个时刻点上仍只有一个进程在运行
原因就是cpu性能太猛了,通过时钟滴答方式,在进程间切换进而实现看起来并发的效果

2.1 单道程序设计

所有进程一个一个排队执行。若A阻塞,B只能等待。(DOS系统)

2.2 多道程序设计

在计算机内存中同时存放几道相互独立的程序,它们在管理程序控制之下,相互穿插的运行。多道程序设计必须有硬件基础作为保证。

时钟中断(时钟滴答)! 一个时间片后强制让进程让出cpu,进而在多道程序设计模型中,多个进程轮流使用CPU(分时复用CPU资源)

本质上!!!并发是宏观的并行,微光的串行!!!!!

3. MMU(Memory Management Unit, 内存管理单元)

MMU 实现了虚拟内存与物理内存的映射!!!!

每个进程在运行时,将分配0~4G的虚拟内存,通过MMU映射到真实的内存地址上

4. PCB(进程控制块)

每个进程在内核中(3G~4G虚拟空间中)都有一个进程控制块(PCB)来维护进程相关的信息,PCB本质是 task_struct 结构体

  1. 进程id
  2. 进程状态(初始态、就绪态、运行态、挂起态、终止态)5种/4种(将初始和就绪合并)
  3. 进程切换需要保存和恢复的一些CPU寄存器
  4. 描述虚拟地址空间的信息
  5. 描述控制终端的信息
  6. 当前工作目录
  7. umask掩码
  8. 文件描述符
  9. 信号相关信息
  10. 用户id和组id
  11. 会话和进程组
  12. 进程可以使用的资源上限

5. fork 创建子进程

5.1 头文件包含及函数声明

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

pid_t fork(void);

5.2 pid_t fork(void)

创建子进程。父子进程各自返回。

成功:父进程返回子进程pid,子进程返回0
失败:父进程返回-1,子进程没有创建,设置errno

5.3 getpid、getppid

pid_t getpid(void);  		返回当前进程id
pid_t getppid(vodi);		返回当前进程的父进程id

5.4 demo

/* fork.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>

int main(int argc, char *argv[])
{
	printf("before fork -1-\n");
	printf("before fork -2-\n");
	printf("before fork -3-\n");
	printf("before fork -4-\n");

	pid_t pid = fork();
	if(pid == -1)
	{
		perror("fork error");
		exit(0);
	}else if(pid == 0)
	{
		printf("--child is created, pid=%d, parent-pid=%d\n", getpid(), getppid());
	}else if(pid > 0)
	{
		printf("---parent process:my child is %d, my_pid=%d, my_parent-pid=%d\n", pid, getpid(), getppid());
	}

	printf("=============end of file\n");
	return 0;
}

成功创建一个子进程,并和父进程各自打印各自的进程id和父进程id

6. 循环创建n个子进程 (demo loop_fork.c)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>

int main(int argc, char *argv[])
{
        int i;
        pid_t pid;

        for(i=0; i<5; i++)
        {
                if((pid = fork()) == 0)
                        break;
        }

        if(i == 5)
        {
                //sleep(5);     防止父子进程抢占CPU
                printf("I'm parent \n");
        }
        else if(i<5)
        {
                //sleep(i);
                printf("I'm %dth child\n",i+1);
        }
        return 0;
}

结果!!! 会出现父子进程抢占CPU的情况,且bash会先一步打印进程工作目录

fork之后父进程先执行还是子进程先执行不确定。取决于内核所使用的调度算法。
出现子进程和父进程争夺cpu的情况,打印顺序会打乱
会出现子进程没有争过bash的情况

解决:

sleep( )
延迟调用线程,会被挂起设定的时间time,time后会被继续调用,但是需要看系统操作是否繁忙。

7. 父子进程异同

父子进程相同:

刚fork之后,data段,text段,堆,栈,环境变量,全局变量、宿主目录位置、进程工作目录位置、信号处理方式

父子进程不同:

进程id、返回值、各自的父进程、进程创建的时间、闹钟、未决信号集

父子进程共享:读时共享,写时复制 !!!

  1. 文件描述符(打开文件结构体)
  2. mmap建立的映射区(进程间的通信详解)

7.1 demo 父子进程间的共享(全局变量)

/* fork_shared.c */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>

int var = 100;

int main(void)
{
	pid_t pid;
	
	pid = fork();

	if(pid < 0)
	{
		perror("fork error");
		exit(1);
	}
	else if(pid > 0)
	{
		var = 288;
		printf("parent,var = %d\n", var);
		printf("I'am parent pid=%d,getppid = %d\n",getpid(), getppid());
	}
	else if(pid == 0)
	{
		var=200;
		printf("child,var = %d\n", var);
		printf("I'am child pid = %d,ppid = %d\n", getpid(), getppid());
	}
	printf("--------finish------------\n");
}

读时共享,写时复制!!!,父子进程全局变量不同

8. gdb 调试

使用gdb调试的时候,gdb只能跟踪一个进程。可以在fork函数 调用之前,通过指令设置gdb调试工具跟踪父进程或者时跟踪子进程。默认跟踪父进程

set follow-fork-mode child 		 	命令设置gdb在fork之后跟踪子进程
set follow-fork-mode parent 		设置跟踪父进程

以 loop_fork.out 为例:

调试子进程:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值