本文测试代码的运行环境:
Centos7 x86_64
Kernel 3.10.0-693.5.2.el7.x86_64
gcc 版本 4.8.5
CPU:2 核

线程概念

线程是运行在进程之中的一个处理任务的分支,一个进程都包括一个主线程。
进程:资源分配、管理的基本单位(管理内存、管理打开的文件等)。
线程:调度、执行的基本单位。
在 Linux 中线程也叫做轻量级进程 ==LWP==。
每次创建一个新的进程,会分配一个新的虚拟地址空间。
每次创建一个新的线程,线程共用原来的虚拟地址空间。

从 Linux 内核的角度来说,其实它并没有线程的概念。Linux 把所有线程都当做进程来实现,它将线程和进程不加区分的统一到了 task_struct 中。

线程之间共用的资源

  1. 虚拟地址空间。
  2. 文件描述符表。

线程创建的时候,加上了 CLONE_VM 标记,这样==线程的内存描述符将直接指向父进程的内存描述符。==

1
2
3
4
5
if (clone_flags & CLONE_VM) {
// current 是父进程而 tsk 在 fork() 执行期间是共享子进程
atomic_inc(&current->mm->mm_users);
tsk->mm = current->mm;
}

线程之间不共用的资源

  1. 栈。
  2. 上下文信息(寄存器信息)。
  3. errno(每个线程有自己单独的错误码)。

对于 Linux 进程或者说主线程,其 stack 是在 fork 的时候生成的,实际上就是复制了父亲的 stack 空间地址,然后写时拷贝 (cow) 以及动态增长。
然而对于主线程生成的子线程而言,其 stack 将不再是这样的了,而是事先固定下来的。
线程栈不能动态增长,一旦用尽就没了,这是和生成进程的 fork 不同的地方。

线程的优点

相比于进程来说:

  1. 创建和销毁开销更小。
  2. 切换调度的开销更小。
  3. 线程占用的资源更小。

多线程程序能够充分利用多核处理器。
栗子:==因为我的虚拟机是 2 核的,所以 CPU 最多使用是 200%==
在这里插入图片描述

线程的缺点

  1. 程序的健壮性降低,一个线程的异常终止会导致整个进程异常终止。
  2. 编程 && 调试难度增加(引入了线程安全问题)。

线程的用途

  1. 提升 CPU 密集型程序执行效率。
  2. 提高 IO 密集型程序的体验。
    • 通过网络进行 IO。
    • 响应 UI 界面。

EOF