linux下进程与线程对比总结

        学习了unix环境编程这本书和网上的一些文章之后做的一些总结,图是网上扒的(侵删),相关文章链接我放在最后啦。 

 

目录

一. 进程

1. 定义及简单理解

2. 一些注意点

3. 优缺点

4. 一些常用相关函数

二. 线程

1. 定义及简单理解

2. 一些注意点

3. 优缺点

4. 一些常用相关函数(类使用过程)

三. 对比总结

四. 使用的小建议(此处多带一个多路复用和协程)


一. 进程

1. 定义及简单理解

  • 定义:正在运行的程序及其占用的资源(CPU,内存,系统资源等)叫做进程。
  • 理解:在登QQ和别人聊天的同时也可以播放网易云音乐听歌,此处的QQ和网易云音乐就是两个进程,关闭其中一个并不会影响另一个的运行。 

2. 一些注意点

(1)进程与程序的区别:程序是数据和指令的集合, 是一个静态的概念, 就是一堆代码, 可以长时间的保存在系统中;进程是程序运行的过程, 是一个动态的概念, 进程存在着生命周期, 也就是说进程会随着程序的终止而销毁, 不会永久存在系统中。

(2)进程在系统的唯一标识是PID,PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。

(3)要注意僵尸进程。僵尸进程就是已经结束的进程,但是还没有从进程表中删除。僵尸进程太多会导致进程表里面条目满了,进而导致系统崩溃,倒是不占用系统资源。

(4)大家还得注意一下进程池的问题。进程池是资源进程管理进程组成的技术的应用。

定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务;

等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务;

如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。

也就是说,进池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开关进程的时间,也一定程度上能够实现并发效果。 

 

3. 优缺点

(1)优点:

  • 编程简单,非常容易理解。
  • 由于各个进程的地址空间是相互隔离的,因此一个进程崩溃后并不会影响其它进程。
  • 充分利用多核资源。

(2)缺点:

  • 各个进程地址空间相互隔离,这一优点也会变成缺点,那就是进程间要想通信就会变得比较困难,你需要借助进程间通信(IPC,interprocess communications)机制,想一想你现在知道哪些进程间通信机制,然后让你用代码实现呢?显然,进程间通信编程相对复杂,而且性能也是一大问题。
  • 我们知道创建进程开销是比线程要大的,频繁的创建销毁进程无疑会加重系统负担。

4. 一些常用相关函数

  • fork(),vfork():创建子进程。fork()子进程拷贝父进程的数据段,堆栈段,而vfork()子进程与父进程共享数据段,并不复制。fork()父子进程的执行次序不确定,vfork 保证子进程先运行,在调用 exec() 或 exit() 之前与父进程数据是共享的,在它调用 exec*()或 exit() 之后父进程才可能被调度运行,如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。还需要注意的是,vfork()创建子进程成功后是严禁使用return的,只能调用exit()或者exec族的函数,不然会报段错误。
  • getpid(),getppid():获取PID。getpid()是获取父进程或子进程自己的ID号,子进程可以使用getppid()获取父进程的ID号,但是没有API函数能让父进程获取子进程的进程ID。
  • exec*():一系列函数用来执行另外一个程序
  • wait(),waitpid():用来解决僵死进程问题
  • system():用来执行另一个linux命令,常配合snprintf()使用
  • popen():用来执行另一个linux命令,且返回一个基于管道(pipe)的文件流,这样我们就可以从该文件流中一行一行地解析和提取自己需要的数据

二. 线程

 

1. 定义及简单理解

  • 定义:线程是进程的一条执行路径。线程在linux系统下,通常被称为轻量级的进程。
  • 理解:登陆QQ,在列表里点开多个人同时与多个人聊天,此时QQ是一个进程(这时也可以称之为主线程),而其中的每一个聊天窗口都是一个这个进程的线程,关闭其中一个聊天窗口并不会影响别的聊天窗口,但是如果退出QQ程序这些窗口都会退出。

2. 一些注意点

(1)由于线程共享进程地址空间,因此线程间通信天然不需要借助任何通信机制,直接读取内存就好了。线程创建销毁的开销也变小了,要知道线程就像寄居蟹一样,房子(地址空间)都是进程的,自己只是一个租客,因此非常的轻量级,创建销毁的开销也非常小。

(2)由于线程共享进程地址空间,这在为线程间通信带来便利的同时也带来了无尽的麻烦。正是由于线程间共享地址空间,因此一个线程崩溃会导致整个进程崩溃退出,同时线程间通信简直太简单了,简单到线程间通信只需要直接读取内存就可以了,也简单到出现问题也极其容易,死锁、线程间的同步互斥、等等,这些极容易产生bug,无数程序员宝贵的时间就有相当一部分用来解决多线程带来的无尽问题。虽然线程也有缺点,但是相比多进程来说,线程更有优势,但想单纯的利用多线程就能解决高并发问题也是不切实际的。因为虽然线程创建开销相比进程小,但依然也是有开销的,对于动辄数万数十万的链接的高并发服务器来说,创建数万个线程会有性能问题,这包括内存占用、线程间切换,也就是调度的开销。

 

3. 优缺点

(1)优点:

  • 线程执行开销小
  • 线程产生的速度快,线程间的通讯快,切换快等,因为线程在同一地址空间内。
  • 线程的资源率比较好,也是因为它们在同一地址空间内。

(2)缺点:

  • 线程执行开销小
  • 多进程每个进程有自己的地址空间,线程则共享地址空间
  • 线程使用公共变量/内存时需要使用同步机制,要学习会用互斥锁

4. 一些常用相关函数(类使用过程)

  • pthread_attr_init(&thread_attr);  //对参数结构体进行初始化,后再设置属性
  • pthread_attr_setstacksize(&thread_attr, 120*1024);  //设置栈大小(局部变量防在栈中)。一般默认的栈大小是够的,若有很多很多局部变量,觉得栈大小不够就用这个函数进行修改。
  • Pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);  //子线程创建后默认为可会合模式,用这个函数和对应参数设置成相分离模式,主线程不用等子线程与之汇合,子线程一旦运行结束进入终止状态,就自动销毁释放系统资源。
  • Pthread_create(&tid, &thread_attr, thread_worker1, &shared_var);  //创建子线程
  • 创建完后子线程的id号放在tid中,thread_attr为子给线程设置的属性,whread_worker1为子线程所要执行的功能(一般为一个自定义函数),shared_var为传给该函数的参数(如果是多个参数该怎么办?可以传一个结构体,如果不要这个参数就传NULL)
  • Pthread_attr_destroy(&thread_attr); //子线程的属性在设置完后,调用该函数销毁属性结构体,与init是对应的。
  • Pthread_exit(NULL);  //子线程中不能调用exit()函数,会导致整个进程退出。

三. 对比总结

        进程是资源管理的最小单位,线程是程序执行的最小单位。进程为细胞,线程就相当于元素。创建进程与线程都需要占用资源,都需要耗费时间。

        一个进程可以有很多个线程, 每条线程并行执行不同的任务,线程可以共享进程中的所有资源,也可以共享主线程的所有资源,但线程与线程之间的资源相互独立,不可访问与使用。

        父进程和子进程,主线程和子线程之间谁先执行都没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。如果需要确保让父进程或子进程先执行,则需要程序员在代码中通过进程间通信的机制(IPC)来自己实现,而线程要注意互斥锁的使用。

        在线程中(相对与进程而言),线程是一个更加接近执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。这两者都可以提高程序的并发度,提高程序运行的效率和响应的时间。

        线程可以提高应用程序在多核环境下处理诸如文件I/O或者socket I/O等会产生堵塞的情况的表现性能。在Unix系统中,一个进程包含很多东西,包括可执行程序以及一大堆的诸如文件描述符地址空间等资源。在很多情况下,完成相关任务的不同代码间需要交换数据。如果采用多进程的方式,进程的创建所花的时间片要比线程大些,另外进程间的通信比较麻烦,需要在用户空间和内核空间进行频繁的切换,开销很大。但是如果使用多线程的方式,因为可以使用共享的全局变量,所以线程间的通信(数据交换)变得非常高效。

        多线程是十字路口多线程是平面交通系统,造价低,但是红绿灯多,老堵车,而多进程是则是立交桥,虽然造价高,上下坡多耗油,但是不堵车。

四. 使用的小建议(此处多带一个多路复用和协程)

要做到同时服务多个客户端,主要有三种技术:

1. 多进程,各进程空间独立彼此对彼此影响不显著,只能开到当前cpu个数的进程,要在程序中执行另一个程序得用这个方法,能用来处理计算型任务 ,开销最大。

2. 如果并行不必要(例不太在意阻塞的问题、要注意的公共资源并不多),那么可以考虑用线程并发,单位开销比进程小很多。

    线程:并发(轮询调度,遇到阻塞就切换)

    只要是网络,就会有延迟,有延迟就阻塞,所以比一般的单路要好些。

3. 如果轮询不必要,可考虑是否可以只需要遇到阻塞切换。

    此时可以用IO多路复用技术 + 协程来实现阻塞切换,消耗资源很少,并发量最高。关于多路复用之后我也会写一个总结的文章。

相关文章链接:

Linux 系统进程、线程之间的爱恨纠葛

还有一个名为“码农的荒岛求生”的公众号相关文章,链接容易挂放不上来抱歉了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值