进程和线程的概念、区别和联系

进程(process)和线程(thread)是操做系统的基本概念,可是它们比较抽象,不容易掌握。html

最近,我读到一篇材料,发现有一个很好的类比,能够把它们解释地清晰易懂。linux

进程与线程的一个简单解释编程

在这个简单易懂的类比下,了解一下进程和线程的宏观概念安全

进程,是并发执行的程序在执行过程当中分配和管理资源的基本单位,是一个动态概念,竟争计算机系统资源的基本单位。每个进程都有一个本身的地址空间,即进程空间或(虚空间)。进程空间的大小 只与处理机的位数有关,一个 16 位长处理机的进程空间大小为 216 ,而 32 位处理机的进程空间大小为 232 。进程至少有 5 种基本状态,它们是:初始态,执行态,等待状态,就绪状态,终止状态。服务器

线程,在网络或多用户环境下,一个服务器一般须要接收大量且不肯定数量用户的并发请求,为每个请求都建立一个进程显然是行不通的,——不管是从系统资源开销方面或是响应用户请求的效率方面来看。所以,操做系统中线程的概念便被引进了。线程,是进程的一部分,一个没有线程的进程能够被看做是单线程的。线程有时又被称为轻权进程或轻量级进程,也是 CPU 调度的一个基本单位网络

说到这里,咱们对进程与线程都有了一个大致上的印象,如今开始说说两者大体的区别数据结构

    进程的执行过程是线状的,尽管中间会发生中断或暂停,但该进程所拥有的资源只为该线状执行过程服务。一旦发生进程上下文切换,这些资源都是要被保护起来的。这是进程宏观上的执行过程。而进程又可有单线程进程与多线程进程两种。咱们知道,进程有 一个进程控制块 PCB ,相关程序段 和 该程序段对其进行操做的数据结构集 这三部分,单线程进程的执行过程在宏观上是线性的,微观上也只有单一的执行过程;而多线程进程在宏观上的执行过程一样为线性的,但微观上却能够有多个执行操做(线程),如不一样代码片断以及相关的数据结构集。线程的改变只表明了 CPU 执行过程的改变,而没有发生进程所拥有的资源变化了 CPU 以外,计算机内的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。与进程控制表和 PCB 类似,每一个线程也有本身的线程控制表 TCB ,而这个 TCB 中所保存的线程状态信息则要比 PCB 表少得多,这些信息主要是相关指针用堆栈(系统栈和用户栈),寄存器中的状态数据。进程拥有一个完整的虚拟地址空间,不依赖于线程而独立存在;反之,线程是进程的一部分,没有本身的地址空间,与进程内的其余线程一块儿共享分配给该进程的全部资源多线程

    线程能够有效地提升系统的执行效率,但并非在全部计算机系统中都是适用的,如某些不多作进程调度和切换的实时系统。使用线程的好处是有多个任务须要处理机处理时,减小处理机的切换时间;并且,线程的建立和结束所须要的系统开销也比进程的建立和结束要小得多。最适用使用线程的系统是多处理机系统和网络系统或分布式系统。并发

 

线程在执行过程当中与进程仍是有区别的。每一个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。可是线程不可以独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 分布式

 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分能够同时执行。但操做系统并无将多个线程看作多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

1. 线程的执行特性。

    线程只有 3 个基本状态:就绪,执行,阻塞。

    线程存在 5 种基本操做来切换线程的状态:派生,阻塞,激活,调度,结束。

2. 进程通讯。

    单机系统中进程通讯有 4 种形式:主从式,会话式,消息或邮箱机制,共享存储区方式。

    主从式典型例子:终端控制进程和终端进程。

    会话式典型例子:用户进程与磁盘管理进程之间的通讯。

 

关于多进程和多线程:

一.为什么须要多进程(或者多线程),为什么须要并发?

这个问题或许自己都不是个问题。可是对于没有接触过多进程编程的朋友来讲,他们确实没法感觉到并发的魅力以及必要性。

我想,只要你不是成天都写那种int main()到底的代码的人,那么或多或少你会遇到代码响应不够用的状况,也应该有尝过并发编程的甜头。就像一个快餐点的服务员,既要在前台接待客户点餐,又要接电话送外卖,没有分身术确定会忙得你焦头烂额的。幸运的是确实有这么一种技术,让你能够像孙悟空同样分身,灵魂出窍,乐哉乐哉地轻松应付一切情况,这就是多进程/线程技术。

并发技术,就是可让你在同一时间同时执行多条任务的技术。你的代码将不只仅是从上到下,从左到右这样规规矩矩的一条线执行。你能够一条线在main函数里跟你的客户交流,另外一条线,你早就把你外卖送到了其余客户的手里。

因此,为什么须要并发?由于咱们须要更强大的功能,提供更多的服务,因此并发,必不可少。

二.多进程

什么是进程。最直观的就是一个个pid,官方的说法就:进程是程序在计算机上的一次执行活动。

说得简单点,下面这段代码执行的时候

 
int main()  
  
{  
  
printf(”pid is %d/n”,getpid() );  
  
return 0;  
  
}  

进入main函数,这就是一个进程,进程pid会打印出来,而后运行到return,该函数就退出,而后因为该函数是该进程的惟一的一次执行,因此return后,该进程也会退出。

看看多进程。linux下建立子进程的调用是fork();

#include <unistd.h>  
#include <sys/types.h>   
#include <stdio.h>  
  
   
  
void print_exit()  
{  
       printf("the exit pid:%d/n",getpid() );  
}  
  
main ()   
{   
   pid_t pid;   
   atexit( print_exit );      //注册该进程退出时的回调函数  
      pid=fork();   
        if (pid < 0)   
                printf("error in fork!");   
        else if (pid == 0)   
                printf("i am the child process, my process id is %d/n",getpid());   
        else   
        {  
               printf("i am the parent process, my process id is %d/n",getpid());   
              sleep(2);  
              wait();  
       }  
  
}  

i am the child process, my process id is 15806
the exit pid:15806
i am the parent process, my process id is 15805
the exit pid:15805

这是gcc测试下的运行结果。

关于fork函数,功能就是产生子进程,因为前面说过,进程就是执行的流程活动。

那么fork产生子进程的表现就是它会返回2次,一次返回0,顺序执行下面的代码。这是子进程。

一次返回子进程的pid,也顺序执行下面的代码,这是父进程。

(为什么父进程须要获取子进程的pid呢?这个有不少缘由,其中一个缘由:看最后的wait,就知道父进程等待子进程的终结后,处理其task_struct结构,不然会产生僵尸进程,扯远了,有兴趣能够本身google)。

若是fork失败,会返回-1.

额外说下atexit( print_exit ); 须要的参数确定是函数的调用地址。

这里的print_exit 是函数名仍是函数指针呢?答案是函数指针,函数名永远都只是一串无用的字符串。

某本书上的规则:函数名在用于非函数调用的时候,都等效于函数指针。

 

说到子进程只是一个额外的流程,那他跟父进程的联系和区别是什么呢?

我很想建议你看看linux内核的注解(有兴趣能够看看,那里才有本质上的了解),总之,fork后,子进程会复制父进程的task_struct结构,并为子进程的堆栈分配物理页。理论上来讲,子进程应该完整地复制父进程的堆,栈以及数据空间,可是2者共享正文段。

关于写时复制:因为通常 fork后面都接着exec,因此,如今的 fork都在用写时复制的技术,顾名思意,就是,数据段,堆,栈,一开始并不复制,由父,子进程共享,并将这些内存设置为只读。直到父,子进程一方尝试写这些区域,则内核才为须要修改的那片内存拷贝副本。这样作能够提升 fork的效率。

三.多线程

线程是可执行代码的可分派单元。这个名称来源于“执行的线索”的概念。在基于线程的多任务的环境中,全部进程有至少一个线程,可是它们能够具备多个任务。这意味着单个程序能够并发执行两个或者多个任务。

简而言之,线程就是把一个进程分为不少片,每一片均可以是一个独立的流程。这已经明显不一样于多进程了,进程是一个拷贝的流程,而线程只是把一条河流截成不少条小溪。它没有拷贝这些额外的开销,可是仅仅是现存的一条河流,就被多线程技术几乎无开销地转成不少条小流程,它的伟大就在于它少之又少的系统开销。(固然伟大的后面又引起了重入性等种种问题,这个后面慢慢比较)。

关于多线程与多进程,线程安全,函数可重入详见http://blog.csdn.net/hairetz/article/details/4281931/

相关文章
相关标签/搜索