Linux应用层开发(三)进程与线程简述

Linux的多任务处理机制

多任务机制:就是说可以在电操作系统种同时执行多个应用程序的能力。
在CPU(单核)种实际上在某一时刻只能执行一个任务,而多任务机制就是用时间片轮转算法;
在每个任务被创建的时候被分配时间片(几十到几百毫秒),任务执行(占用CPU)时,时间片就会递减,当时间片为0的时候就去执行其他任务,其他任务又分配时间片,然后又消耗其他任务的时间片,当其他任务都做完了,又切换回来。由于任务切换会很频繁,间隔时间很短,所以用户感觉很多任务在同一时刻运行。
多任务操作系统种通常有3个基本概念:任务,进程,线程。

任务

任务是什么:一个逻辑概念,通常一个任务时一个程序的一次运行,一个任务包括一个或者多个完成独立功能的子任务,这个独立的子任务,可能时进程,也可能是线程。
在这里插入图片描述

进程的基本概念

进程是什么:一个具有独立功能的程序,在某个数据集合上的一次动态执行过程,它是操作系统进行资源分配和调度的基本单元。一次任务运行可以激活多个进程,这些进程相互合作来完成完成该任务的一个终极目标。
进程的主要特性:
1)并发性:一个系统上可以有多个进程同时并发执行,相互不干扰
2)动态性:指的是进程都具有完整的生命周期,进程的生命周期内,进程的状态是不断变化的,进程具有动态的地址空间(包括代码,数据,进程控制模块等)。
3)交互性:进程可以和其他进程进行直接或间接通信,如进程的同步和互斥,需要为此添加一定的进程处理机制
4)独立性:指的是进程是个相对完整的资源分配和调度的基本单位,各个进程之间地址空间是相互独立的,只有采取某些特定的通信机制才能实现进程之间的通信。

进程和程序的区别

进程和程序是有本质的区别的
程序:是一段静态的代码,是保存在非易失性存储器上指令和数据的有序集合,没有任何执行的概念
进程:是一个动态的概念,他是程序的一次执行过程,包括动态创建,调度,执行和消亡的过程,它是程序执行和资源分配的最小单位。

Linux进程的分类

1)交互式进程。这类进程经常和用户进行交互,需要等待用户的输入,接受到用户的输入之后,这类进程会能够立刻响应,典型的有shell命令进程,文本编辑器等
2)批处理进程:这类进程不需要和用户交互,这类进程通常不需要即时响应,因此往往不会优先调度。典型的批处理进程是编译器的编译操作,数据库搜索引擎等。
3)守护进程:这类进程一直运行在后台,和任何终端不关联。通常系统启动开始执行,系统关闭才结束。很多系统进程(各种服务)都是以守护进程的形式存在。

进程的结构

进程不但包括程序的数据和指令集合,而且包括程序计数器和处理器
的所有寄存器以及存储临时数据的进程堆栈。

Linux是一个多任务的操作系统,所以其他进程必须等到操作系统将处理器使用权分配给自己才能运行,当正在运行的程序需要等待其他的系统资源时,Linux内核将处理器的控制权,按照某种调度算法将处理器分配给正在等待执行的程序。

内核所有程序放在双向循环链表种,链表的每一项都是task_struct,称为进程控制块的结构,该结构包含了一个进程相关的所有信息,在<include/Linux/sched.h>文件中定义,task_struct内核结构比较大,它能完整地描述一个进程,如进程的状态,进程的基本信息,进程的标识符,内存相关信息,父进程相关信息,与进程相关的终端信息,当前工作目录,打开的文件信息,所接受的信号和信号信息

task_struct结构中最为重要的两个域:state(进程状态),和pid(进程标识符)。

(1)进程状态。

Linux中的进程有以下几种主要状态。
1)运行态(TASK_RUNNING):进程正在运行或则和在运行队列中等待调度
2)可中断的阻塞状态(TASK_INTERRUPTBLE):进程处于阻塞状态(睡眠)状态,正在等待某些事件发生或者能够占用某些资源。处在这种状态下的进程可以被信号中断。接收到信号或被显示地唤醒呼叫(如调wake_up系列的宏定义:wake_up,wake_up_interruptible等)唤醒之后,进程将转变为TASK_RUNNIG状态。
3)不可中断的阻塞状态(TASK_UNINTERRUPTBLE),这个状态无法被信号中断,不能改变它的状态,必须要等到对应的事件发生,才会被显示地唤醒
4)暂停状态(TASK_STOPPED)。进程的执行被暂停,当进程收到SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU等信号,就会进入暂停状态
5)僵死状态:(EXIT_STOPPED)。子进程运行结束,父进程未退出,并且未使用wait函数族使用系统调用来回收子进程的退出状态。处于该状态下的子进程已经放弃了几乎所有的内核空间,没有可执行的代码,也不能被调度,仅仅在进程表中保留一个位置,记载进程的退出状态等信息供父进程收集。
6)消亡状态(EXIT_DEAD)。这是最终状态,父进程调用wait函数族回收之后,子进程由系统彻底删除,不可见。

(2)进程标识符。
Linux内核通过位移的进程标识符PID来标识每个进程。PID存放在Task_struct的pid字段中。系统中可以创建的进程数目有限,可以通过/proc/sys/kernnel/pid_max来确定上限。
当系统启动以后一个指向Task_struct的宏current用来记录正在运行的进程。current经常作为进程描述符结构指针的形式出现在内核代码中,如current->pid表示处理器正在执行的进程的PID。当系统需要查看所有的进程时,调用for_each_process()宏,这将比系统搜索数组的速度要快得多。
在Linux中获取当前进程得进程号(PID)和父进程(PPID)的函数分别为getpid(),getppid()

3.进程的创建和执行

许多操作系统都提供产生进程的机制,也就是首先在新的地址空间里创建进程,读入可执行文件,最后再开始执行。
Linux的创建很特别,它把上述步骤分解到两个单独的函数中执行:fork()和exec()函数族。首先fork()通过复制当前进程创建一个子进程,子进程与父进程的区别仅仅在于不同的PID,PPID和某些资源及统计量。exec函数族负责读取可执行文件,并且将其载入地址空间开始运行。
注意Linux中fork()使用的是写时复制(copy on write)的技术,也就是内核再创建进程时,其资源并没有立刻被复制过来,而是被推迟到需要写入数据的时候才发生。在此前,只是以只读的方式来共享父进程的资源。写时复制技术可以使Linux拥有快速执行的能力,这个优化很重要。

进程的内存结构

Linux操作系统采用虚拟内存管理,使得每个进程都有独立的地址空间。该地址的大小为4GB的线性虚拟空间,
用户所看到和接触到的都是该虚拟地址,无法看到实的物理内存地址。利用这种虚拟地址不但更安全(用户不能直接访问物理内存),而且用户程序可以使用比物理内存更大的地址空间。
4GB的进程地址空间会被分为两部分:用户空间,内核空间。用户空间是0~~3GB(0XC0000000),内核空间占3~4GB。
用户进程在通常情况下只能访问用户空间的虚拟地址,不能访问内核空间虚拟地址。
只有用户进程使用系统调用(代表用户进程在内核态执行)时才可以访问到内核空间。每当进程切换,用户空间就会跟着改变,而内核空间是内核负责映射,它并不会跟着进程改变,是固定的。内核空间有自己对应的页表,用户进程各自有不同的页表,每个进程的用户空间都是完全独立,互不相干的。进程的虚拟内存地址空间如图所示
也就是,对于子进程和父进程公有的资源,其虚拟地址是一样的,并且其物理地址在进程不发生分歧的时候也是一样的,如果发生分歧,其物理地址会不一样。但是虚拟地址一样,也就是说不同的进程对应页表映射的物理空间可能是不相同的。

在这里插入图片描述

** 箭头:是指地址从高地址向低地址或者从低地址向高地址增长**

文件映射段:从低地址向高地址增长。
动态连接器链接:动态库。
共享的内存映射区:共享内存。

线程

线程可以称为轻量级的进程,线程可以对进程的内存空间和资源进行访问,并与同一进程的其他线程共享。而每个进程都拥有独立的堆栈段,数据段,代码段。进程切换的开销明显不线程要大。
线程与进程的关系图如下
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值