进程与线程详解

来源:互联网 发布:少女前线ios数据清空 编辑:程序博客网 时间:2024/06/07 01:10

本文参考于《操作系统真相还原》

1、执行流的概念

  我们首先来介绍一下执行流的概念,执行流就是一段逻辑上独立的指令区域,对应于代码,大到可以是整个程序文件,即进程,小到可以是一个功能独立的代码块,即函数,而线程本质上就是函数。执行流是独立的,其独立性体现在每个执行流都有自己的栈、一套自己的寄存器映像和内存资源,其实这就是执行流的上下文环境。因此,我们要想构造一个执行流,就要为其提供一整套的资源。因此,任何代码块,无论大小都可以独立成为执行流,只要在它运行的时候,我们提前准备好它所依赖的上下文环境即可,这里的上下文环境就是它所使用的寄存器映像、栈、内存等资源。

  那么,成为独立的执行流有什么用呢?在任务调度器的眼里,只有执行流才是调度单元,即处理器上运行的,每个任务都是调度器给分配的执行流,只要成为执行流就能够独立上处理器运行了,也就是说可以分配处理器的时间,处理器会专门分时来处理这个执行流中的指令。

2、线程到底是什么?

首先,我们通过一段代码来感受一下线程的创建:

#linclude<stdio.h>#include<pthread .h >voi d* thread_func (void* _arg) {    ...}void main() {  pthread_t new thread id;  pthread_create(&new_thread_i d, NULL , thread_func , &new_thread_id);  printf (”main thread: my tid is %u\n ”, pthread_ self () ) ;  usleep (100);}
由这段代码我们看出一段端倪,线程其实就是运行一段函数的载体。在高级语言中,线程是运行函数的另一种方式,那这种方式和普通的函数调用有什么区别呢?要回答这个问题,涉及到调度单元问题。调度器每次安排一个执行流上处理器,之前在介绍执行流的时候强调过了,其实任何代码都可以独立,只要在运行的时候,我们给它准备好所依赖的上下文环境就可以。只要是独立的执行流就可以被调度器视为一个调度单元,可以被调度器选中,然后享受处理器的单独服务。我们要做的是:给任何想单独上处理器的代码块准备好它所依赖的上下文环境,从而使其独立,成为执行流,即调度单元。

在一般的函数调用中,它并不是独立的,是跟着此函数所在的调度单元一块上处理器运行的,这个调度单元也许是整个进程,或者线程,总之是混在更大的执行流中被捎带执行,甚至有可能还未执行到此函数它的时间片就到了,从而被换下了处理器,如下图所示:

图中可以看出,把普通函数提升其独立性,变为执行流后,受到调度器的青睐几率大大增加。其实说白了,线程就是一套机制,此机制可以为一般的代码块创造它所依赖的上下文环境,从而让代码块具有独立性,因而在原理上线程能使一段函数成为调度单元,即执行流,从而能够被专门调度到处理器上执行。

3、进程与线程的关系和区别简述

程序是指静态的、存储在文件系统上、尚未运行的指令代码,他是实际运行时程序的映像。进程是指正在运行的程序,即进行中的程序,程序必须在获得运行所需要的各类资源后才能成为进程,资源包括栈、寄存器等。

对于处理器来说,进程是一种控制流集合,集合中至少包含一条执行流,执行流之间是相互独立的,但它们共享进程的所有资源,它们是处理器的执行单元,或者成为调度单位,它们就是进程。可以说,线程是在进程的基础之上的二次开发。按照进程中线程数量来划分,进程分为单线程进程和多线程进程。我们平时所写的程序,如果其中未显示创建线程,它就属于单线程进程,即只包含单个执行流,这就是我们平时所指的传统型进程,否则就属于多线程进程。

我们在操作系统中学过,每个进程都运行在自己的地址空间中,话说有内存空间才能存储资源,因此进程拥有此程序运行所需的全部资源。默认情况下进程只有一个执行流,即一个进程只能干一件事。有些情况下,我们需要在一个地址空间中存在多个执行流,即让进程同时并行很多事,这多个执行流指的就是线程。执行流就是调度器的调度单位,是处理器的执行单元,线程在此方面和进程的行为是一致的,只不过线程不包括位于进程中的、自己所需的资源,言外之意是线程没有自己独享的地址空间,没有空间就没办法存储自己的资源,所以线程必须活在进程的世界里,借助空间中的资源运行。

线程仅仅是个执行流,并不是什么高深莫测的东西,它只是被一些线程实现机制增加的神秘感。比如像POSIX线程库中的pthread_create函数,它的功能是用来创建线程,第三个实参必须是一个事先定义好的函数,这个作为参数的函数就是我们所说的代码块。线程是在进程之后才提出的概念,在没有线程之前,进程就是理所当然的执行流,或者说进程只是一个大的执行流。在有了线程的概念后(仅仅是在名词概念之后,其实线程这玩意一直存在),执行流便专指粒度更细的线程,因此线程是最小的执行单元。

那么为什么要有线程这个概念呢?为了给程序提速,确切的说是给进程提速,因为线程必然属于某一进程,线程要运行必须有相应的资源,而进程就是这个资源的提供者。利用线程提速,原理就是实现多个执行流的伪并行。进程采用多个执行流和其他进行抢处理器资源,这样就节省了单个进程的总执行时间。提速的原理很简单,就是想办法让处理器多执行自己进程中的代码,这样进程执行完成得就快。比如任务队列中有100个任务,看似其它任务都是在和自己竞争处理器资源,但是其实有98个执行流都是在帮自己做事,那么相比之下,自己执行的就比另一个快。线程另一个提速的原理就是避免了阻塞整个进程。

说到这里,可以用一个表达式来表述进程与线程的关系:进程=线程+资源。

举个例子:比如在饭店里,只要有人点菜,厨房就开始忙活。厨房相当于进程,里面有食材和烹饪的工具,这些都是资源,在厨房工作的人有厨师、配菜员、餐具清洁员等,他们都是进程中的线程。比如客人点了一盘鱼香肉丝,厨房中各类角色就要开始并行工作,配菜员开始准备食材,厨师负责烹饪。他们只能在厨房工作,出了厨房,配菜员无菜可配,厨师无菜可烹。通过这个例子,我们可以说:进程拥有整个地址空间,其中包括各种资源,而进程中的所有线程共享一个地址空间,因为地址空间中有线程运行所需要的资源。

总的来说:

1、线程是一种机制,可以使得代码块获取所依赖的上下文环境,成为独立的执行流

2、进程是控制流的集合,执行流+资源的封装

原创粉丝点击