澳门威尼娱乐网址进程切换与线程切换的区别?

注意这个题目问的是进程切换与线程切换的区别,不是进程与线程的区别。当然这里的线程指的是同一个进程中的线程。这个问题能很好的考察面试者对进程和线程的理解深度,有比较高的区分度。要想正确回答这个问题,面试者需要理解虚拟内存。

进程间切换的步骤:

进程与线程的区别,进程线程区别

今天就讲一下进程和线程是什么?有什么区别?

进程,进程和线程的区别

原文链接:

一、进程

    每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,linux内核的进程控制块是task_struct结构体,其中有:

  • 进程id。系统中每个进程有一个唯一的id,在C语言中用pid_t类型表示,是一个非负正是

  • 进程的状态,有运行、挂起、停止、僵尸等状态

  • 进程切换时需要保存和恢复的一些CPU寄存器

  • 描述虚拟地址空间的信息

  • 描述控制终端的信息

  • 当前工作目录

  • umask掩码

  • 文件描述符表,包含很多指向file结构体的指针

  • 和信号相关的信息

  • 用户id和组

  • 控制终端、Session和进程组。

  • 进程可以使用的资源上限

 

    fork的作用是根据一个现有的进程(父进程)复制出一个新进程(子进程),系统中同时运行着多个进程,这些进程都是从最初只有一个进程开始一个一个复制出来的,在Shell下输入命令可以运行一个程序,是因为Shell进程在读取用户输入的命令之后会调用fork复制出一个新的Shell进程,然后新Shell进程调用exec执行新的程序。

    一个程序可以多次加载到内存中成为同时运行的多个进程,例如可以同时开多个终端运行/bin/bash。一个进程在调用exec前后也可以分别执行两个不同的程序,例如在Shell下输入命令ls,首先fork创建子进程,这时子进程仍在执行/bin/bash程序然后子进程调用exec执行新的程序/bin/ls。如下图所示:

    澳门威尼娱乐网址 1

    子进程的PCB是根据父进程复制而来的,所以其中的umask掩码也和父进程一样。同样道理子进程的当前工作目录也和父进程一样,所以我们用cd改变Shell进程的工作目录,然后ls列出那个目录下的文件,ls进程其实是在列自己的当前目录,而不是Shell进程的当前目录,只不过ls进程的目录和Shell的目录一样。但是子进程PCB中的进程id和父进程不同。

    

二、环境变量

 

    exec系统调用执行新程序时会把命令行参数和环境变量表传递给main函数,它们在整个进程地址空间中的位置如下所示:

    澳门威尼娱乐网址 2

    和命令行参数argv类似,环境变量表也是一组字符串,如下图所示:

    澳门威尼娱乐网址 3

    libc定义的全局变量environ指向环境变量表,environ没有包含在头文件中,所以在使用时要用extern声明。例:

#include <stdio.h>

int main(void)
{
    extern char **environ;
    int i;
    for (i=0; environ[i] != NULL; i++)
        printf("%s\n", environ[i]);
    
    return 0;
}

    执行结果为:

    澳门威尼娱乐网址 4

    由于父进程在调用fork创建子进程时会把自己的环境变量表也复制给子进程,所以打印的环境变量和Shell进程打印的环境变量是相同的。环境变量定义了进程的运行环境。

    可以用char *getenv(const char
*name)获取name在环境变量表中对应的value。

    可以用int setenv(const char *name, const char *value, int
rewrite);设置环境变量。

    可以用void unsetenv(const char *name);删除name的定义。

    在子进程中修改环境变量并不会改变父进程的环境变量。

原文链接: 一、进程
每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,li…

进程
“进程”
两字,我第一次看到应该是在用Windows系统时,当我的软件卡死,没办法退出,我会调出任务管理器,然后看到上面有各种进程,其中运行着我的各种已经打开的软件,所以我通俗地把他理解为系统里面的一个应用程序。

虚拟内存解放生产力

1,保存程序计数其以及其他寄存器。

进程:

书面定义:

  • 狭义定义:进程是正在运行的程序的实例(an instance of a computer
    program that is being executed)。
  • 广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

自己对于进程的理解:要以一个整体的形式暴露给操作系统管理,里面包含对各种资源的调用,内存管理,网络接口的调用等…对各种资源管理的集合就可以称为进程。

对于进程最主要的概念有两点:

进程的特征:

  • 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
  • 并发性:任何进程都可以同其它进程一起并发执行。
  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的数度向前推进。

多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

在这里就引进了程序的概念。

线程
“线程”两字,是我做iOS开发之后才看到的,在我的理解就是,CPU处理多任务时,有些任务是可以一个一个地按顺序执行,但是同时也有一些任务是必须同时进行,就像我们在进行网络请求时,因为这个操作是一个相对较耗时的操作,如果我们让CPU按顺序去执行这些操作的话,那我们在网络请求的过程中去点击界面,我们将会比较久才得到响应(俗称卡顿),这是因为CPU要处理完网络请求之后才会处理我们点击的相应,这样就造成很差的用户体验,由此,多线程就产生了,而线程就是我们CPU运行这个应用程序时开的一条处理任务的路径,多线程就是我们CPU在执行多个任务时开了多条路径,各自在个自的线程上执行,互不影响,从而避免了界面的卡顿。
以上是我自己的理解,下面贴上知乎上面一个解释地比较专业和透彻的回答:

对于程序员来说,我们在编程时实际上是不怎么操心内存问题的,对于使用Java、Python、JavaScript等动态类型语言的程序员来说更是如此,自动内存回收机制的引入使得使用这类语言的程序员几乎完全不用关心内存问题;即使对于编译型语言C/C++来说,程序员需要关心的也仅仅是内存的申请和释放。

2,更新当前处于“运行态”的进程的进程控制块,把进程状态改为相应状态,更新其他相关域

程序:

程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。

程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。

首先来一句概括的总论:进程和线程都是一个时间段的描述,是CPU工作时间段的描述。
下面细说背景:CPU+RAM+各种资源(比如显卡,光驱,键盘,GPS,
等等外设)构成我们的电脑,但是电脑的运行,实际就是CPU和相关寄存器以及RAM之间的事情。
一个最最基础的事实:CPU太快,太快,太快了,寄存器仅仅能够追的上他的脚步,RAM和别的挂在各总线上的设备完全是望其项背。那当多个任务要执行的时候怎么办呢?轮流着来?或者谁优先级高谁来?不管怎么样的策略,一句话就是在CPU看来就是轮流着来。
一个必须知道的事实:执行一段程序代码,实现一个功能的过程介绍

总的来说,作为程序员(无论使用什么类型的语言)我们根本就不关心数据以及程序被放在了物理内存的哪个位置上(设计实现操作系统的程序员除外),我们可以简单的认为我们的程序独占内存,比如在32位系统下我们的进程占用的内存空间为4G;并且我们可以申请超过物理内存大小的空间,比如在只有256MB的系统上程序员可以申请1G大小的内存空间,这种假设极大的解放了程序员的生产力。

3,把被切换进程的进程控制块移到相关状态的队列

线程:

线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。

,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CPU开始执行。这里除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就要被切换出去,等待下一次CPU的临幸。在被切换出去的最后一步工作就是保存程序上下文,因为这个是下次他被CPU临幸的运行环境,必须保存。串联起来的事实:前面讲过在CPU看来所有的任务都是一个一个的轮流执行的,具体的轮流方法就是:先加载程序A的上下文,然后开始执行A,保存程序A的上下文,调入下一个要执行的程序B的程序上下文,然后开始执行B,保存程序B的上下文。。。。

而这种假设实现的背后功臣就是虚拟内存。

4,选择另外一个进程开始执行,把该进程进程控制块的状态改为“运行态”

进程和线程的区别:

进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

可以归纳为以下几点:

今天就讲一下进程和线程是什么?有什么区别? 进程: 书面定义:
狭义定义:进程是正在运行的程序的…

重要的东西出现了========进程和线程就是这样的背景出来的,两个名词不过是对应的CPU时间段的描述,名词就是这样的功能。进程就是包换上下文切换的程序执行时间总和

CPU加载上下文+CPU执行+CPU保存上下文线程是什么呢?进程的颗粒度太大,每次都要有上下的调入,保存,调出。如果我们把进程比喻为一个运行在电脑上的软件,那么一个软件的执行不可能是一条逻辑执行的,必定有多个分支和多个程序段,就好比要实现程序A,实际分成
a,b,c等多个块组合而成。那么这里具体的执行就可能变成:程序A得到CPU
=》CPU加载上下文,开始执行程序A的a小段,然后执行A的b小段,然后再执行A的c小段,最后CPU保存A的上下文。这里a,b,c的执行是共享了A的上下文,CPU在执行的时候没有进行上下文切换的。这里的a,b,c就是线程,也就是说线程是共享了进程的上下文环境,的更为细小的CPU时间段。
到此全文结束,再一个总结:进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同。

最后,我再打个简单比喻:
进程就像我国的铁路局运营的所有高铁站,线程就像每个高铁站里面的线路,例如广州站里面有去湖南的线路,有去厦门的线路、有去云南的线路。

以上为我个人理解,如有不对或者不全,欢迎更正和补充,谢谢!

什么是虚拟内存

5,恢复被选择进程的处理器在最近一次被切换出运行态时的上下文,比如载入程序计数器以及其他处理器的值

虚拟内存是操作系统为每个进程提供的一种抽象,每个进程都有属于自己的、私有的、地址连续的虚拟内存,当然我们知道最终进程的数据及代码必然要放到物理内存上,那么必须有某种机制能记住虚拟地址空间中的某个数据被放到了哪个物理内存地址上,这就是所谓的地址空间映射,也就是虚拟内存地址与物理内存地址的映射关系,那么操作系统是如何记住这种映射关系的呢,答案就是页表,页表中记录了虚拟内存地址到物理内存地址的映射关系。有了页表就可以将虚拟地址转换为物理内存地址了,这种机制就是虚拟内存。

 

每个进程都有自己的虚拟地址空间,进程内的所有线程共享进程的虚拟地址空间。

进程间切换伴随着两次模式切换(用户–内核,内核–用户)。

现在我们就可以来回答这个面试题了。

 

进程切换与线程切换的区别

(同一进程内)线程间切换的步骤:
线程分两种,用户级线程和内核级线程

进程切换与线程切换的一个最主要区别就在于进程切换涉及到虚拟地址空间的切换而线程切换则不会。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。

在用户级线程中,有关线程管理的所有工作都由应用程序完成,内核没有意识到线程的存在。
(同一进程内)用户级线程间切换时,只需要保存用户寄存器的内容,程序计数器,栈指针,不需要模式切换。

举一个不太恰当的例子,线程切换就好比你从主卧走到次卧,反正主卧和次卧都在同一个房子中(虚拟地址空间),因此你无需换鞋子、换衣服等等。但是进程切换就不一样了,进程切换就好比从你家到别人家,这是两个不同的房子(不同的虚拟地址空间),出发时要换好衣服、鞋子等等,到别人家后还要再换鞋子等等。

缺点:
1,在进程的某个线程执行系统调用时,不仅该线程被阻塞,该线程所在进程的所有线程都被阻塞
2,无法利用多处理器

因此我们可以形象的认为线程是处在同一个屋檐下的,这里的屋檐就是虚拟地址空间,因此线程间切换无需虚拟地址空间的切换;而进程则不同,两个不同进程位于不同的屋檐下,即进程位于不同的虚拟地址空间,因此进程切换涉及到虚拟地址空间的切换,这也是为什么进程切换要比线程切换慢的原因。

在内核级线程中,有关线程的管理工作都是由内核完成的,应用程序部分没有线程管理的权限,只有一个接口(API)

有的同学可能还是不太明白,为什么虚拟地址空间切换会比较耗时呢?

(同一进程内)内核级线程间切换时,除了保存上下文,还要进行模式切换。

为什么虚拟地址切换很慢

优点:
1,可以利用多处理器
2,线程阻塞不会导致进程阻塞

现在我们已经知道了进程都有自己的虚拟地址空间,把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用Cache来缓存常用的地址映射,这样可以加速页表查找,这个cache就是TLB,Translation
Lookaside
Buffer,我们不需要关心这个名字只需要知道TLB本质上就是一个cache,是用来加速页表查找的。由于每个进程都有自己的虚拟地址空间,那么显然每个进程都有自己的页表,那么当进程切换后页表也要进行切换,页表切换后TLB就失效了,cache失效导致命中率降低,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致TLB失效,因为线程线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。

 

原文链接 

发表评论

电子邮件地址不会被公开。 必填项已用*标注