线程与进程的简单比较

  本篇文章主要对线程与进程之间的区别作一简单总结,从内核实现的区别,双方的地址空间、共享的数据、操作原语的比较和多线程与多进程的区别这几方面,做一简单说明。

1、Linux内核线程实现原理
  Unix系统中,早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切。
  1. 轻量级进程(light-weight process),也有PCB,创建线程使用的底层函数和进程一样,都是clone
  2. 从内核里看进程和线程是一样的,都有各自不同的PCB,但是PCB中指向内存资源的三级页表是相同的
  3. 进程可以蜕变成线程
  4. 线程可看做寄存器和栈的集合;每一个线程都有自己的函数调用,所以其拥有自己的用户栈空间;内核区也有一个栈空间用来保存寄存器的值(cpu为不同的线程分配时间片,在不同的线程间切换)
需要拥有自己的内核栈空间。

2、进程与线程的地址空间
  对于进程来说,相同的地址(同一个虚拟地址)在不同的进程中,反复使用而不冲突。原因是他们虽虚拟址一样,但,页目录、页表、物理页面各不相同。相同的虚拟址,映射到不同的物理页面内存单元,最终访问不同的物理页面。
  但是,线程不同!两个线程具有各自独立的PCB,但共享同一个页目录,也就共享同一个页表和物理页面。所以两个PCB共享一个地址空间。
  实际上,无论是创建进程的fork,还是创建线程的pthread_create,底层实现都是调用同一个内核函数clone。如果复制对方的地址空间,那么就产出一个“进程”;如果共享对方的地址空间,就产生一个“线程”。
因此:Linux内核是不区分进程和线程的。只在用户层面上进行区分。所以,线程所有操作函数 pthread_* 是库函数,而非系统调用。

3、为什么说在linux下,线程最是小的执行单位;进程是最小的分配资源单位?
  当进程调用pthread_create函数后就蜕变成一个线程,经过多次pthread_create后就有了多个线程,而线程和进程的地位是一样的,当cpu在分配时间轮片时会一视同仁。所以说线程是cpu调度的最小单位;而无论在一个进程中创建多少个线程,它们都共享一个0~4G的内存空间,所以说cpu分配资源是以进程为基本单位的。
4、线程默认共享数据段、代码段等地址空间,常用的是全局变量。而进程不共享全局变量,只能借助mmap。
测试:1、进程之间不共享全局变量

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>

int a = 10;
int main()
{
    pid_t pid ,wpid;
    int status;
    pid = fork();

    if(pid < 0)
    {
        perror("fork error!\n");
    }
    else if(pid > 0)  //父进程
    {
        a = 20;

        wpid = wait(&status);
        if(WIFEXITED(status))
        {
            printf("The child process %d exit normally\n",wpid);
            printf("return value:%d\n",WEXITSTATUS(status));
        }
        else if(WIFSIGNALED(status))
        {
            printf("The child process exit abnormally, killed by signal %d\n",WTERMSIG(status));
        }
        else
        {

        }
    }
    else
    {
        sleep(2);
        printf("a = %d\n",a);
    }


    return 0;

}

运行结果如下:可以看出,父子进程不共享全局变量

➜  test git:(master) ✗ ./a.out 
fa process wrote a = 20
a = 10
The child process 11937 exit normally
return value:0

测试线程间共享全局变量,代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>

int var = 10;

void *fun(void *agr)
{
    var = 20;
    printf("pthread!\n");

    return NULL;
}

int main()
{
    pthread_t tid;
    int ret;
    int* retval;

    printf("before pthread_create: var = %d\n",var);

    ret = pthread_create(&tid,NULL,fun,NULL);

    if(ret != 0)
    {
        fprintf(stderr,"pthread_create error : %s\n",strerror(ret));
        exit(1); 
    }

    sleep(1);
    printf("after pthread: var = %d\n",var);

    pthread_join(tid,(void**)&retval);

    return 0;
}

运行结果:线程间共享全局变量

before pthread_create: var = 10
pthread!
after pthread: var = 20

5、进程与线程控制原语对比

进程 线程 作用
fork() pthread_create() 创建
exit() pthread_exit() 退出
wait()/waitpid() pthread_join() 回收资源
kill() pthread _cancel() 杀死进程、线程
getpid() pthread_self() 获取当前进程/线程号

6、多线程与多进程的区别

对比维度 多进程 多线程 总结
数据共享、同步 数据共享复杂,需要IPC;数据是分开的,同步简单 因为共享进程数据,数据共享简单,因此,同步复杂 各有优势
内存、CPU 占用内存多,切换复杂、CPU利用率低 占用内存少,切换简单,CPU利用率高 线程占优
创建销毁、切换 创建销毁、切换复杂,速度慢 创建销毁、切换简单,速度快 线程占优
编程、调试 编程简单、调试简单 编程复杂、调试复杂 进程占优
可靠性 进程间不会影响 一个线程挂掉将会导致整个进程挂掉 进程占优
分布式 适用于多核、多机分布式;扩展机器简单 适用于多核分布式 进程占优

猜你喜欢

转载自blog.csdn.net/z_ryan/article/details/79631252