进程和线程相关的疑问?

[TOC]

进程和线程的区别?

1.拥有资源

进程是资源分配的基本单位,但是线程不拥有资源,线程可以访问隶属进程的资源。

2.调度

线程是独立调度的基本单位,在同一进程中,线程的切换不会引起进程切换,从一个进程中的线程切换到另一个进程
中的线程时,会引起进程切换。

3.系统开销

由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、I/O 设备等,所付出的开销远大于创建或撤销
线程时的开销。类似地,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而
线程切换时只需保存和设置少量寄存器内容,开销很小。

4.通信方面

线程间可以通过直接读写同一进程中的数据进行通信,但是进程通信需要借助 IPC。

进程被分配的是哪些资源?

操作系统通过PCB来描述进程。它就是一个结构体,用来描述进程,在Linux下,就是task_struct结构体。

每个进程运行的时候,都会拿到4G的虚拟内存,在32位Linux下,其中3G是交给用户的,1G是交给内核的,而task_struct就是存储在这1G的内核系统空间中。

每个进程都有各自的私有用户空间(0-3G),这个空间对系统中的其他进程是不可见的。
最高的1GB内核空间则为所有进程以及内核所共享。
至于为什么需要这个1G的内核空间,是因为进程需要调用一些系统调用,来交给内核跑,程序的一部分逻辑可能是要交给内核去跑的,所以一部分虚拟地址必须要留给内核使用。

img

我们常说的虚拟地址空间, 其实就是用户空间。

PCB拥有的内容?

我们可以挑几个重点的记一下

标识相关:pid
文件相关:进程需要记录打开的文件信息,于是需要文件描述符表
内存相关:内存指针,指向进程的虚拟地址空间(用户空间)信息
优先级相关:进程相对于其他进程的调度优先级
上下文信息相关:CPU的所有寄存器中的值、进程的状态以及堆栈上的内容,当内核需要切换到另一个进程时,需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。
状态相关:进程当前的状态,说明该进程处于什么状态
I/O相关:记录进程与各种I/O设备之间的交互

img

image-20210329110415635

线程共享哪些资源

进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、进程用户ID与进程组ID。

线程私有哪些资源?

1.线程ID
每个线程都有自己的线程ID,这个ID在本进程中是唯一的。进程用此来标识线程。

2.寄存器组的值
由于线程间是并发运行的,每个线程有自己不同的运行线索,当从一个线 程切换到另一个线程上 时,必须将原有的线程的寄存器集合的状态保存,以便将来该线程在被重新切换到时能得以恢复。

3.线程的堆栈
堆栈是保证线程独立运行所必须的。线程函数可以调用函数,而被调用函数中又是可以层层嵌套的,所以线程 必须拥有自己的函数堆栈, 使得函数调用可以正常执行,不受其他线程的影响。
4.线程的优先级
由于线程需要像进程那样能够被调度,那么就必须要有可供调度使用的参数,这个参数就是线程的优先级。

程序计数器的作用

程序计数器是用于存放下一条指令所在单元的地址的地方。

当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。

线程切换保存的上下文?

线程在切换的过程中需要保存当前线程Id、线程状态、堆栈、寄存器状态等信息。其中寄存器主要包括SP PC EAX等寄存器,其主要功能如下:
SP:堆栈指针,指向当前栈的栈顶地址

PC:程序计数器,存储下一条将要执行的指令

EAX:累加寄存器,用于加法乘法的缺省寄存器

进程切换保存的上下文?

CPU的所有寄存器中的值、进程的状态以及堆栈上的内容。当内核需要切换到另一个进程时,需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

进程切换和线程切换的区别是什么?

进程上下文切换与线程上下文切换最主要的区别就是线程的切换虚拟空间内存是相同的(因为都是属于自己的进程),但是,进程切换的虚拟空间内存则是不同的。

为什么线程切换开销更小?

进程切换比线程切换开销大是因为进程切换时往往伴随着页调度,因为进程的数据段代码段要换出去,以便把将要执行的进程的内容换进来。

中断的概念?

用户态和内核态的区别

哪些系统调用会从用户态切换到内核态

image-20210322205829246

一台机器最多有多少个进程?

一.Linux中有一个命令可以帮助我们查看系统中的进程上限

1
2
[pigff@izbp13yd4r85qvk53t04mbz ~]$ ulimit -u
4096

这属于软限制,是可以改变的。也就是说在我的机器上最多可以有4096个进程,但是我可以通过改变这个参数的值来修改对于进程数量的软限制,比如说用下面的命令将软限制改到5120。

1
ulimit -u 5120

二.我们用pid_t来表示一个进程的pid,因此能表示的进程的范围一定不会超过pid_t类型的大小

1
2
[pigff@izbp13yd4r85qvk53t04mbz ~]$ cat /proc/sys/kernel/pid_max
32768

所以上面的命令返回32768,这意味着我可以在我的系统中同时执行32768个进程,这些进程可以在不同的内存空间中运行。

一个系统能有多少个线程?

这取决于分配给线程的调用栈大小,可以用ulimit -s命令来查看大小(一般常见的有10M或者是8M)。

1
2
$ ulimit -s
8192

我们还知道,一个进程的虚拟内存是4G,在Linux32位平台下,内核分走了1G,留给用户用的只有3G,于是我们可以想到,创建一个线程占有了10M内存,总共有3G内存可以使用。于是可想而知,最多可以创建差不多300个左右的线程。

因此,进程最多可以创建的线程数是根据分配给调用栈的大小,以及操作系统(32位和64位不同)共同决定的。

上面的命令将输出返回为126406,这意味着我可以在共享内存空间中拥有126406个线程

1
2
cat /proc/sys/kernel/threads-max
126406

协程的相关疑问

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

进程的内存段

img

在将应用程序加载到内存空间执行时,操作系统负责代码段、数据段和BSS段的加载,并在内存中为这些段分配空间。栈也由操作系统分配和管理;堆由程序员自己管理,即显式地申请和释放空间。

BSS段、数据段和代码段是可执行程序编译时的分段,运行时还需要栈和堆。