不时回到根源,重新看一看那些基本概念是很有意思的。看得足够仔细,总能对这些已知概念产生新的想法,像是从老朋友身上发现以前不知道的一面。这个过程似乎是没有止境的,如同分形,不管尺度放大多少倍,总能看到一样的图形。最近的机缘是看到进程和线程的概念。
Sierpinski carpet进程
进程是对一个独立运行程序的抽象。写一个最基本的C语言hello world
代码,编译后在终端里运行这个程序,操作系统就多了一进程; 程序结束,对应的进程也在操作系统中终止了。
但是,既然已经有了程序的概念,又为何多此一举再弄出进程的概念?不妨将应用程序(Application)、源码(Code)、进程(Process)三个概念进行对比。应用程序是一个面向用户的概念,是辅助或代替用户完成某种工作,服务用户,娱乐用户的东西;用户点击图标启动它,用手指、鼠标、键盘控制它。源码是面向程序员的概念,是控制计算机实现应用程序的一系列指令; 它的指令可能是在屏幕上画一个框,或者是一种算法的逻辑。进程是面向操作系统的概念,抽象地描述一个程序; 一切是为了实现多任务,将CPU和内存等资源分配给多个不同的程序; 快速地在不同程序之间切换,一会执行这个程序,一会执行另一个程序; 如些一来,即使一个单核单线程的CPU,也能给人它在同时处理多个程序的错觉。
用进程描述一个程序,操作系统为进程定义了内存空间、外部资源描述、安全信息描述和进程状态描述等。内存空间存储着代码和数据,后者分布在栈与堆中; 随着程序的运行,当前运行指令的指针不段更新,数据也时时发生变化。外部资源包括文件描述符,套接字,信号量等; 这些在程序本身的状态数据中己经存在,又为何非得单独列出?因为这些资源的生成、运行和管理有赖于操作系统,存在于程序状态里的资源信息很难为操作系统所使用。安全信息有进程的拥有者及权限等信息。
线程
进程是一个独立的存在,运行时它像独占着计算资源。独立性使它简单。编程时,进程不是一个特别需要关心的慨念,除了需要进程间通信的场景。
进程实现了计算机同时运行多个程序,线程对进程的进一步发展,使一个程序同时运行多个任务。线程的实现可以在操作系统的内核之中,也可以在用户空间进行实现;前者为核线程,后者为用户线程。
对于核线程,与进程之间的独立性不同,属于同一进程的多个线程之间是有密切关系的。它们执行内存中同一份代码,共享着全局数据空间,使用相同的堆,但具有各自的栈。它们共享着外部资源和安全描述,但有不同的运行状态描述。进程是操作系统分配计算资源的最小单位,线程是其调度的最小单位。对于用户线程,调度可分为两层,首先操作系统调度分配出一段CPU时间,然后用户层另一个调度器再进行调度,将CPU时间再分配给多个用户线程。
线程之间共享资源,方便了线程间通信过程,加快了线程间的调度。一个线程想获得另一个线程的信息,只需调用相应内存即可,无须其他通信手段。问题是,这块共同调用的内存要作特殊处理,保证共一时刻只有一个线程对其执行读写操作,称之为同步; 否则,内存里信息可能发生混乱,导致程序出现不可遇料的行为。线程同步是多线程编程最重要且最难的部分,难在同步问题的出现有不确定性,表现出的症状不同,难以重现。
对于单核单线程处理器,同一时刻处理器内只处理一个线程代码;对于单核多线程处理器,不同线程被调度到不同处理线程同时处理; 对于多核多线程处理器呢?
其他
线程不是唯一一种程序同时处理多个任务的方法,比如基于事件的编程也实现多任务。不同方法之间不是相互独立的,可作混合实现。总之,理论的分类研究和现实的具体实际不同。
网友评论