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()系统调用,因而进程由系统删除。
删除僵死状态的方法只有两个:
- 改写父进程,具体做法是接管SIGCHLD信号。子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。这是基于这样的原理:就算父进程没有调用wait,内核也会向它发送SIGCHLD消息,尽管对的默认处理是忽略,如果想响应这个消息,可以设置一个处理函数。
- 杀死父进程,那么僵死的子进程就会有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类对象保存了对当前访问某一个指定资源的线程的计数值,该计数值是当前还可以使用该资源的线程数目。
其他类似的还有读写锁,条件变量,自旋锁。
进程同步的几种方式:
- 管道(有名,无名)
- 消息队列
- 临界区
- 共享内存
- 信号量
- 套接字