目录
1.Linux线程的概念
1.1 什么是线程?
线程就是进程内的一个执行流。进程相信大家都了解过了,那执行流又是什么呢?下面先简单回顾一下进程的概念,顺便引出线程的含义!
在以前的学习中我们知道,进程=内核数据结构+进程对应的代码和数据。每个进程有自己的PCB(task_struct),虚拟地址空间(虚拟内存里面决定了进程能够看到的“资源”。),页表,还有所映射的物理地址。下图为一个进程的模型结构

如果我们把虚拟内存中的各个区域,页表都划分为若干个小区域,一部分供当前的进程使用。接着再创建几个"进程PCB",此时创建的“进程”不进行写时拷贝,不创建进程地址空间和页表。和task_struct指向同一个进程地址空间、页表,如下图所示。
对这种情况该如何解释呢?对只创建PCB,从当前的进程分配资源的执行流就叫做线程。因为我们可以通过虚拟地址空间+页表对进程进行资源划分,单个"进程"执行粒度,一定要比之前的进程要细。线程再进程的地址空间内运行,拥有该进程的一部分资源。通俗一点讲就是进程内的所有线程组成了一个进程。线程负责进程的部分代码。
经过上面的叙述,那么我们可以重新叙述进程,就是多个PCB,一个进程地址空间,多级页表,所映射对应的物理内存。这里的每个PCB可以称之为轻量级进程。那么我们之前讲的进程是什么呢?其实它是包含一个线程的进程。
1.2 进程和线程的区别
从上面看,进程和线程是紧密相关联的,那么他俩的区别又是什么呢?
进程 |
线程 |
承担分配系统资源的基本实体 (用来整体申请资源) |
CPU调度的基本单位 (向进程要资源) |
进程具有独立性 | 线程的大部分资源是共享的 |
代码数据和数据结构的总和 | 只占有进程部分的资源 |
得出几点结论:
- Linux内核中没有真正意义的线程,使用进程PCB来模拟线程的
- 站在CPU的视角,每一个PCB,都可以称之为轻量级进程
- Linux线程是CPU调度的基本单位,进程是承担分配系统资源的基本单位
- 进程使用来整体申请资源的,线程向进程要资源
- Linux无法直接提供创建线程的系统调用接口,只能提供创建轻量级进程的接口。
1.3 线程的优缺点
优点 | 缺点 |
创建线程比创建进程代价小 | 健壮性/鲁棒性较差 |
线程切换比进程切换要简单的多 | 编写与调试难度提高 |
线程占用的资源较少 | 缺乏访问控制 |
可以并行运行 | |
计算密集型应用,I/O密集型应用 |
2.线程控制
2.1 线程创建
2.1.1 函数介绍
#include <pthread.h>
int pthread_create(pthrea_t* thread, const pthread_att_t* attr, void*(*start_routine)(void*), void* arg);
参数:
- pthread_t* thread:相当于无符号的整型,这里暂且称之为线程id
- const pthread_att_t* attr:设置线程的属性,当前先设置为nullptr
- void*(*start_routine)(void*):函数指针,线程将要执行的该函数
- void* arg:将传入上面函数的参数
返回值:成功返回0,失败返回错误码。
使用此方法必须链接libpthread-2.17.so原生线程库。任何Linux都必须默认携带改库。编译时加
-lpthread选项。
命令行查看线程的命令:ps -aL
PID和LWP相同的为主线程,不同的为新线程。CPU调度时,是以LWP为标识符表示特定一个执行流的。
2.1.2 多线程具体的实现
代码1:
#include <iostream>
#include <cassert>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>
using namespace std;
void func();
// 新线程
void *thread_routine(void *args)
{
const char *name = (const char*)args;
while(1)
{
cout << "我是新线程, 名字为:" << name << ":";
fflush(stdout);
sleep(1);
}
}
int main()
{
pthread_t tid;
int n = pthread_create(&tid, nullptr, thread_routine, (void*)"thread one");
assert(n == 0);
(void)n;
while(1)
{
char tidbuffer[64];
snprintf(tidbuffer, sizeof(tidbuffer), "0x%x", tid);
cout << "我是主线程,我创建出来的线程id为:" << tidbuffer << ":" ;
fflush(stdout);
sleep(1);
}
return 0;
}
结果: