您的位置:首页 > 其它

线程与进程的简单比较

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

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利用率高线程占优
创建销毁、切换创建销毁、切换复杂,速度慢创建销毁、切换简单,速度快线程占优
编程、调试编程简单、调试简单编程复杂、调试复杂进程占优
可靠性进程间不会影响一个线程挂掉将会导致整个进程挂掉进程占优
分布式适用于多核、多机分布式;扩展机器简单适用于多核分布式进程占优
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: