进程与线程

进程

   进程被称为执行中的程序,但程序本身不是进程,只是被动实体,而进程是活动实体,是资源分配的最小单位。

两个进程可以与同一程序相关,但是它们是两个独立的执行序列。如一个用户能调用多个web浏览器程序副本,但这些都是独立进程。

进程不仅仅是程序代码,进程还包括当前活动(通过程序计数器的值和寄存器的内容来表示)

线程

CPU使用的基本单元,由线程ID、程序计数器、寄存器集合和栈组成,线程是任务调度和程序执行的最小单位

它与属于同一进程的其他线程共享代码段、数据段,其独有的:栈(保存其运行状态和局部自动变量)、程序计数器。

线程基本状态:就绪、阻塞和运行三种基本状态。

就绪状态,指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;

运行状态,指线程占有处理机正在运行;

阻塞状态,指线程在等待一个事件(如信号量),逻辑上不可执行。

优点:1.响应度高(如多线程的Web浏览器在用一个线程装入图像时是,能够通过另一线程与用户交互)

2.资源共享(线程可以共享程序和数据)

3.经济(进程创建和切换昂贵,创建切换线程更经济)

4.充分利用多处理器体系。(多线程使得每个 进程可以并行地运行在不同地处理器上)

协程

协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:
协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。


协程的好处:

  1. 无需线程上下文切换的开销
  2. 无需原子操作锁定及同步的开销
  3. 方便切换控制流,简化编程模型

高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。


缺点:

  1. 无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
  2. 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序(

    假设协程运行在线程之上,并且协程调用了一个阻塞IO操作,这时候会发生什么?实际上操作系统并不知道协程的存在,它只知道线程,因此在协程调用阻塞IO操作的时候,操作系统会让线程进入阻塞状态,当前的协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度,这往往是不能接受的。

进程与线程的区别

一个程序至少有一个进程,一个进程至少有一个线程.

1.进程是资源分配的最小单位,线程是任务调度和程序执行的最小单位
2.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。

而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。

3.线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据;协作进程之间通信需要进程间通信机制(IPC)(共享内存(在共享区域读写信息)、消息传递)

4.多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

同步与互斥

同步:多个任务之间有依赖关系,某个任务的运行依赖于另一个任务。

互斥:多个任务都需要访问/使用同一种资源一个公共资源同一时刻只能被一个进程或线程使用,多个进程或线程不能同时使用公共资源。

互斥锁:互斥锁是一种简单的加锁的方法来控制对临界区资源(临界区资源:产生互斥;不是所有的共享资源都是临界资源)的访问,互斥锁只有两种状态,即上锁( lock )和解锁。

1. 在访问共享资源后临界区域前,对互斥锁进行加锁;

2. 对互斥锁进行加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放

3. 在访问完成后释放互斥锁导上的锁。

条件变量

条件变量用来自动阻塞一个线程,直 到某特殊情况发生为止

通常条件变量和互斥锁同时使用,互斥锁用于上锁,条件变量用于等待

线程在改变条件状态之前必须首先锁住互斥量。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件。如果两进程共享可读写的内存,条件变量 可以被用来实现这两进程间的线程同步。

条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步 的一种机制,主要包括两个动作:

  • 一个线程等待"条件变量的条件成立"而挂起;

  • 另一个线程使 “条件成立”(给出条件成立信号)。(如果另一个线程改变了条件,它会发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件

读写锁

读写锁允许更改的并行性,也叫共享互斥锁。互斥量要么是锁住状态,要么就是不加锁状态,而且一次只有一个线程可以对其加锁。

读写锁可以有3种状态:读模式下加锁状态、写模式加锁状态、不加锁状态

  • 如果某线程申请了读锁,其它线程可以再申请读锁,但不能申请写锁;

  • 如果某线程申请了写锁,其它线程不能申请读锁,也不能申请写锁。

信号量

        信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。

  编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞。

        PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1。

  • 僵尸进程

    • 子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。
    •  定义:一个进程使用fork创建子进程,如果子进程退出(即死亡),而父进程并没有调用wait或者waitpid获取子进程的状态信息,那么子进程的进程描述符等一系列信息还会保存在系统中。这种进程称之为僵死进程。
    • 危害:在Unix系统管理中,当用ps命令观察进程的执行状态时,经常看到某些进程的状态栏为defunct,这就是所谓的“僵尸”进程。“僵尸”进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。由于进程表的容量是有限的,所以,defunct进程不仅占用系统的内存资源,影响系统的性能,而且如果其数目太多,还会导致系统瘫痪。
    • 处理方法:
      • 改写父进程,在子进程死后要为它收尸。具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
      • 把父进程杀掉。父进程死后,僵尸进程成为”孤儿进程”,过继给1号进程init,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。
  • 孤儿进程

    一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。
  • 孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值