深入探究进程与线程

线程与进程

在Linux下,程序可执行文件是一个静态的实体,它只是一组指令的集合,没有执行的含义。进程是一个动态的实体,有自己的生命周期。线程是操作系统进程调度器可以调度的最小执行单元。
一个进程可能包含多个线程。

有人说,不必非要使用线程,多个进程也能做到这点。的确如此。
那么线程是不是一种设计上的冗余呢?其实不是这样的。

进程之间,彼此的地址空间时独立的,但线程会共享内存地址空间。同一个进程的多个线程共享一份全局内存区域,包括初始化数据段。未初始化数据段和动态分配的堆内存段。

这种共享给线程带来了很多的优势:

  • 创建和终止线程更加快
  • 线程之间上下文切换的开销,要小于进程之间的上下文切换
  • 线程之间的数据共享比进程之间的数据共享要简单

线程间的上下文切换,指的是同一个进程里不同线程之间发生的上下文切换。由于线程原本属于同一个进程,他们会共享地址空间,大量资源共享,切换的代价小于进程之间的切换时自然而然的事情。

线程之间通信的代价对于进程之间通信的代价。线程共享地址空间的实际,让多个线程之间的通信变得非常简单。进程之间的通信代价则高很多。进程之间不得不采用一些进程间通信的手段(如管道、共享内存及信号量等)来协作。

前面是从操作系统的角度来分析线程优势的,从用户或应用的视角来分析,多线程的程序也有很多的优势

1.发挥多核优势,充分利用CPU资源

对于可并行的程序或者I/O密集型程序,可充分发挥多核cpu的优势,充分利用cpu资源,在相同时间捏处理更多的任务。

2.更自然的编程模型

将工作的分工细分给线程,会更加自然合理。

多线程也存在弊端

  • 多线程的进程,因地址空间的共享让该进程变得更加脆弱,多个线程之中,只有有一个线程出错(比如core)就会导致进程内所有线程一起完蛋。相比之下,进程的地址空间互相独立,彼此隔离的更加彻底,多个进程之间相互协同,一个进程存在bug导致异常退出,不会影响到其他进程。
  • 线程模型作为一种并发的编程模型,效率并没有想象的那么高,会出现复杂度高、易出错、难以测试和定位的问题。多线程生活在进程地址空间这同一个屋檐下,若存在多个线程操作共享资源,则需要同步,否则可能会出现结果错误、数据结构遭到破坏甚至是程序崩溃等结果。因此多线程编程中存在临界区的概念,临界区的代码只允许一个线程执行,线程提供了锁机制来保护临界区。当其他线程来到临界区去无法申请到锁时,就可能陷入阻塞,不再处于可执行状态,线程可能不得不让出cpu资源。如果设计不合理,临界区非常多,线程之间的竞争异常激烈,频繁地上下文切换也会导致性能急剧恶化。

上面两种情况的存在,决定了多线程并非总是处于并发的状态,加速也并非是线性的。由于进程调度的无序性,严格来说多线程的每次执行其实并不一样,很难穷举所有的时序组合,所以我们永远无法宣称多线程的程序经过了充分的测试。

对于多线程编程来说,还存在很多陷阱

  • 死锁

  • 饿死

  • 活锁

  • 竞态条件

    客观地说,多线程编程的难度要更大一些,需要程序员更加小
    心,更加谨慎。当你需要使用多线程的时候,一定要花费足够的时
    间小心地规划每个线程的分工,尽可能地减少线程之间的依赖。良
    好的设计,合理的分工是多线程编程至关重要的环节。若初期随意
    地设计线程的分工,那么在最后,你很有可能不得不花费大量的时
    间来优化性能,定位bug,甚至不得不推倒重来。
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值