进程、轻量级进程和线程(Linux)

1、线程和进程

进程是计算机程序关于某数据集合的一次运行活动,是系统进行资源分配和系统调度的基本单位。进程是程序执行的一个实例。因此如果有16个用户同时执行一个程序,那么就有16个进程,虽然他们共享同一个可执行代码。linux通过进程描述符管理进程

线程是程序执行流的最小单元,一个标准线程由线程ID,当前指令指针PC,寄存器集合,堆栈组成。另外,线程是进程的一个实体,是系统独立调度和分配的基本单位。

1.1 进程描述符

1.1.1 进程状态 state

进程描述符中的state字段描述了进程当前所处的状态,这些状态是互斥的:

  • 可运行状态(TASK_RUNNING ):

进程正在执行或准备执行

  • 可中断的等待状态(TASK_INTERRUPTIBLE):

进程被挂起(睡眠),直到某个条件为真才被唤醒(状态转为可运行状态)。这个条件可能是一个硬件中断、等待的系统资源被释放、得到一个信号。

  • 不可中断的等待状态(TASK_UNINTERRUPTIBLE):

把信号传递到睡眠进程也不能改变其状态,在某些特定情况下才会用到。例如,当进程打开一个设备文件,那么相应的设备驱动文件开始检测设备,在检测完成前,设备驱动程序不能被终端,否则设备将处于不可预知状态。

  • 暂停状态(TASK_STOPPED):

进程执行被暂停

  • 跟踪状态(TASK_TRACED):

进程执行已由debugger程序暂停,当一个进程被另一个进程监控时,任何信号都可以把这个进程置于TASK_TRACED状态

  • 僵死状态(EXIT_ZOMBIE):

进程的执行被终止,但是父进程还没有发布wait(4)或waitpid()系统调用来返回有关死亡进程的消息,因此内核还不能删除死进程描述符中的东西,因为父进程可能还需要它

  • 僵死撤销状态(EXIT_DEAD):

最终状态:由于父进程发出wait4()或waitpid()系统调用,因而进程由系统删除。

删除僵死状态的方法只有两个:

  1. 改写父进程,具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
  2. 杀死父进程,那么僵死的子进程就会有1号进程init接管,init始终会负责清理僵尸进程.它产生的所有僵尸进程也跟着消失。

1.2 进程0和进程1

所有进程的祖先叫做进程0,idle进程;

进程1 即init进程;

1.2 同步和互斥

同步:同步就是协同步调,按预定的先后次序进行运行。

互斥:某些资源 不能同时被多个进程使用,例如打印机

线程同步的几种方式:(类似FreeRTOS中的任务通信)

1、临界区:

CcriticalSection g_CriticalSection;//定义临界区对象
g_CriticalSection.Lock()//在访问共享资源(代码或变量)之前,先获得临界区对象,
g_CriticalSection.Unlock();//访问共享资源后,则放弃临界区对象,

如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。

2、事件:

事件机制,则允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。

线程同步之事件

3、互斥量

互斥对象和临界区对象非常相似,只是其允许在进程间使用,而临界区只限制与同一进程的各个线程之间使用,

但是更节省资源,更有效率。

4、信号量

当需要一个计数器来限制可以使用某共享资源的线程数目时,可以使用“信号量”对象。CSemaphore类对象保存了对当前访问某一个指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程数目。

其他类似的还有读写锁条件变量自旋锁

进程同步的几种方式:

  • 管道(有名,无名)
  • 消息队列
  • 临界区
  • 共享内存
  • 信号量
  • 套接字

 

 


版权声明:本文为weixin_37058227原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。