进程控制块PCB(Process Control Block)node
进程存在的标识,在Linux系统中是task_struct,task_struct在内核栈(Linux进程氛围用户栈和内核栈)的尾端分配。mysql
从低地址到高地址:程序员
进程是拥有资源的基本单位,进程的地址空间相互独立;web
线程是独立调度的基本单位,共享同一个进程内的资源(线程有本身的栈),减小了程序并发时所付出的时空开销,而且能够高效的共享数据,有效地利用多处理器和多核计算机,提升os的并发度。算法
一个进程异常退出不会引发另外的进程运行异常;可是线程若异常退出通常是会引发整个进程奔溃。sql
建立/撤销/切换 进程的开销远大于线程的(建立线程比建立进程快10~100倍 UNPv2/P406)。数据库
孤儿进程 —— 父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工做。安全
僵尸进程 —— 一个进程使用fork建立子进程,若是子进程退出,而父进程并无调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。服务器
守护进程 —— 守护进程的父进程是init进程,由于它真正的父进程在fork出子进程后就先于子进程exit退出了,因此它是一个由init继承的孤儿进程。不须要用户输入就能运行并且提供某种服务,不是对整个系统就是对某个用户程序提供服务。常见的守护进程包括系统日志进程syslogd、 web服务器httpd、邮件服务器sendmail和数据库服务器mysqld等。网络
最大进程数受如下3方面限制:
UNP 分了如下几中形式的IPC:
进程间通讯方式:匿名管道,有名管道,消息队列,共享内存,信号量,套接字,域套接字,信号
线程同步方式:互斥量,条件变量,读写锁
半双工的(即数据只能在一个方向上流动),具备固定的读端和写端;是一种特殊的文件(pipefs,挂载在内核中),有固定大小,只存在于内存中;
实现原理:
管道是由内核管理的一个缓冲区,被设计成为环形的数据结构,以便管道能够被循环利用。当管道中没有信息的话,从管道中读取的进程会等待,直到另外一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另外一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。
在 Linux 中,管道的实现借助了文件系统的file结构和VFS的索引节点inode。经过将两个file结构指向同一个临时的VFS索引节点,而这个VFS索引节点又指向一个物理页面而实现的。
内核会利用必定的机制同步对管道的访问。
半双工,可在无关进程使用;FIFO有路径名与之相关联,以一种特殊设备文件形式存在于文件系统中
实现原理:
Linux中设立了一个专门的特殊文件系统--管道文件,FIFO在文件系统中有对应的路径。当一个进程以读(r)的方式打开该文件,而另外一个进程以写(w)的方式打开该文件,那么内核就会在这两个进程之间创建管道,虽然FIFO在VFS的目录树下可见,可是它并不对应disk上的文件。
本质上是一个先进先出的队列数据结构,最先放入的数据被最早读出来,从而保证信息交流的顺序。FIFO只是借用了文件系统来为管道命名。当删除FIFO文件时,管道链接也随之消失。当进程终止时,管道内的数据会被删除。
共享内存是最快的:
一般往管道、FIFO或消息队列写入数据时,这些IPC须要将数据从进程复制到内核,一般总共须要复制4次,而共享内存则只拷贝2次数据;如图:
用于通知接收进程,有某种事件发生。
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求能够说是同样的。信号是异步的,一个进程没必要经过任何操做来等待信号的到达。
加锁原语,排他性访问共享数据,用于保护临界区。可细分为递归锁/非递归锁。
若是存在某个线程依然使用原先的程序
(即不尝试得到mutex,而直接修改共享变量),互斥锁不能阻止其修改。因此,互斥锁机制须要程序员本身来写出完善的程序来实现互斥锁的功能(如下锁 同样)。
互斥锁用于上锁,条件变量用于等待,条件变量的使用是与互斥锁共通使用的。
条件变量学名叫管程(monitor)【From muduo P40】。
读写锁也叫作 共享-独占锁,容许更高的并发度。
互斥量要么是锁住状态,要么是不加锁状态,并且一次只有一个线程对其加锁。
读写锁能够有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程能够占有写模式的读写锁,可是多个线程可用同时占有读模式的读写锁。
读写锁能够经过使用互斥锁和条件变量来实现。
在获取锁以前一直处于忙等(自旋)阻塞状态;经常使用于
锁被持有的时间短,且线程并不但愿在从新调度上花费太多成本。当线程自旋等待锁变为可用时,CPU不能作其余事情。
故而自旋锁常做为底层原语,用于实现其余类型的锁。
记录锁是读写锁的一种扩展类型,可用于亲缘关系或无亲缘关系的进程之间共享某个文件的读与写。被锁住的文件经过文件描述符进行访问,执行上锁的操做函数是fcntl,这种类型的锁一般在内核中维护。
记录锁的功能是:一个进程正在读或修改文件的某个部分时,能够阻止其余进程修改同一文件区,即其锁定的是文件的一个区域或整个文件。
记录锁有两种类型:共享读锁,独占写锁。基本规则是:多个进程在一个给定的字节上能够有一把共享的读锁,但在一个给定字节上的写锁只能有一个进程独用。即:若是在一个给定的字节上已经有一把读或多把读锁,则不能在该字节上再加写锁;若是在一个字节上已经有一把独占性的写锁,则不能再对它加任何读锁。
处理死锁的策略:
通常来讲,打破循环使用资源最容易,即顺序加减锁
银行家算法(死锁避免算法)。在资源动态分配过程当中,防止系统进入不安全状态,以免发生死锁。
数据库中会用到等待图进行死锁检测
在Linux下,信号量和线程互斥锁的实现都是经过futex系统调用。