初学 多进程多线程

目录

什么是进程

进程执行的两种方法

1.并行

并发

进程的内存分配

进程执行的基础状态

运行态

睡眠态

僵尸态

进程的创建


什么是进程

简单来说进程就是程序执行的过程,它代表程序在干嘛。

如图,在电脑中的任务管理器中就可查看进程,(程序是静态的,保存在磁盘中

程序是静态的它是保存在磁盘上的指令的有序集合,没有任何执行的概念

进程是一个动态的概念它是程序执行的过程,包括了动态创建、调度和销毁的整个过程

进程是受操作系统调度的,一旦有进程产生,就会开辟空间

进程执行的两种方法

1.并行

假如电脑的cpu的核为8核,这个时候来了8个进程,那么每个核负责处理一个进程(你的核越多,处理的进程越多),依赖你的财力。

并发

当你的钱包只能支持你买只有一核的轻薄本时(假设),想让它处理进程速度提高,就可以用并发模式。

可以这样理解:系统把1s分为1000份,每一份执行一个进程,时间到就弹出当下进程,让进程们进行竞争(包括弹出的进程,除非进程执行完),这样就可以提高核的工作效率。

进程的内存分配

在32位的Linux系统中,每一个进程会获得4G的空间,1G的内核空间,3G的用户空间。

当然这是虚拟的空间,不然多来几个进程系统就卡死了

虚拟地址空间中的每个地址都是一个虚拟地址

虚拟地址 : 虚拟地址并不代表真实的内存空间,而是一个用于寻址的编号

物理地址 : 是指内存设备中真实存在的存储空间的编号 虚拟地址通过映射的方式建立与物理地址的关联,从而达到访问虚拟地址就可以访问到对应的物理地址

在 cpu 中有一个硬件 MMU(内存管理单元) ,负责虚拟地址与物理地址的映射管理以及虚拟地址访问 操作系统可以设置 MMU 中的映射内存段

        

在操作系统中使用虚拟地址空间主要是基于以下原因:

1.直接访问物理地址,会导致地址空间没有隔离,很容易导致数据被修改

2.通过虚拟地址空间可以实现每个进程空间都是独立的,操作系统会映射到不用的物理地址区间,在 访问时互不干扰.

进程执行的基础状态

进程的状态很多,这里就说几个比较重要的

运行态

运行态(TASK_RUNNING) : 此时进程或者正在运行,或者准备运行,就绪或者正在进行都属于 运行态

睡眠态

睡眠态(TASK_SLEEP): 此时进程在等待一个事件的发生或某种系统资源 可中断的睡眠(TASK_INTERRUPT) : 可以被信号唤醒或者等待事件或者资源就绪 不可中断的睡眠(可以用scanf 理解)

(TASK_UNTERRUPT) : 只能等待特定的事件或者资源就绪

僵尸态

僵尸态(TASK_ZOMBIE):进程已经结束但是还没有释放进程资源(当父进程结束时会将其销毁)

#include <stdio.h>
int main()
{
        int num=-1;
        printf("please input number:");
        scanf("%d",&num);
        printf("num=%d\n",num);
        return 0;
}

TASK_RUNNING-------->TASK_INTERRUPTIBLE   等待用户输入 用户输入完成后   TASK_INTERRUPTIBLE------------->TASK_RUNNING

程序运行结束   TASK_RUNNING--------->TASK_ZOMBIE

进程的创建

在上面提到一个父进程,每个进程都需要与其它某一个进程建立父子关系,对应的进程叫做父进程。

1. Linux 系统会为每个进程分配id ,这个id作为当前进程的唯一标识,当进程结束,则会被回收。

2. 进程的id与父进程的id分别通过getpid()与getppid()来获取

通过调用fork()函数,则会产生一个新的进程。调用fork()函数的进程叫做 父进程,产生的新进程则为 子 进程。

// 创建一个子进程,并打印 Hello fork
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
        pid_t pid = fork();
        if(pid==-1)
       {
                perror("fork");
                return -1;
       }  
        printf("Hello fork.\n");
        return 0;
}

问题1:为什么显示两次"hello fork"?

fork()函数下都属于子进程所以打印语句在两个进程中都运行了

问题2:为什么两次显示结果有差异?

如果父进程在子进程打印之前结束,则会回到终端命令后继续执行子进程;如果子进程的 打印语句在父进程结束之前执行,则会在回到终端命令前执行完毕

通过fork()创建的子进程的特点:

1.父子进程并发执行,子进程从fork()函数之后开始执行

2.父子进程的执行顺序由操作系统决定,不是程序本身决定

3.子进程会拷贝夫进程地址空间的内容,包括缓存区,文件描述符(子进程会拷贝共享文件状态与文件偏移量等信息)

// 父子进程数据空间拷贝,缓冲区的拷贝
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
        // 标准IO
        write(1,"write hello.",12);
        // 文件IO自带缓冲区
        fputs("fputs hello.",stdout); // 注意没有换行符,stdout的缓冲区属于行
缓冲
        pid_t pid = fork();
        if(pid==-1)
       {
                perror("fork");
                return -1;
       }
        printf("pid = %d,Hello fork.\n",getpid());
        return 0;
}

​​​​​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值