文章目录
- 一.理解Linux线程的本质
- 进程地址空间是进程访问系统资源的窗口
- Linux系统中,线程是比进程更轻量级的执行流
- 二.Linux线程独立运行的原理
- 三.基础线程控制
一.理解Linux线程的本质
进程地址空间是进程访问系统资源的窗口
Linux系统中,线程是比进程更轻量级的执行流
- 线程是进程内部的执行流,同一个进程中,每个线程有独立的
task_struct
内核数据结构对象,但是进程地址空间是共享的,因此可以认为,同一个进程中的多个线程共享所有的代码和数据,线程间天然可通信,具有较高的耦合度 - 线程是内核中进行执行流调度的基本单位,进程是内核中分配系统资源的基本单位
- 一个进程中,所有线程共享进程的CPU调度时间片
- 线程间进行调度切换时,CPU片内缓存
cache
的内部数据(通常是一些指令数据)和进程页表无须换出,只需要切换一些寄存器中的执行流上下文信息即可,因此线程间调度切换比进程间调度切换的效率要高很多,同时线程占用的系统资源也较少,多线程可以有效提高系统的并发量和运行效率(尤其是在有多个执行流调度队列的多核CPU中)
二.Linux线程独立运行的原理
- 同一个进程中,多个线程分配进程系统资源的本质就是分配进程地址空间
- 同一个进程中多个线程并发执行时,每个线程都要有自己独立的栈空间来建立函数栈帧执行函数
- 绝大多数Linux环境中都默认自带
POSIX
第三方线程库(动态库),Linux环境下编写多线程代码需要调用该库进行线程的创建和维护管理 - 每一个线程各自的栈空间和局部存储变量,由
POSIX
线程库统一维护在struct pthread
结构体中,通过动态库链接的方式,映射到进程地址空间的共享区段(用户本质上也可以自己通过系统调用接口自己维护线程栈和局部存储变量,但是比较麻烦,因此有人开发了线程库)
- 主线程栈就是进程地址空间的栈区,其余线程的栈空间统一维护在动态库中,保证了各执行流之间可以相互独立地执行任务
三.基础线程控制
- 多线程编程中,各个非主线程的代码执行流用函数来进行封装,函数的地址作为参数传递给线程创建接口
pthread_create
,线程被创建后,其执行流会立即调用指定函数,主线程通过接口pthread_join
对其他线程进行阻塞等待以获取执行结果 - 一个进程中,一旦主线程退出,该进程中的所有线程都会随之退出
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <error.h>
#include <stdio.h>
#include <string>//任务请求对象
class Request
{
public:Request(int start, int end, const std :: string &threadname): start_(start), end_(end), threadname_(threadname){}
public:int start_;int end_;std :: string threadname_;
};//请求回应对象
class Response
{
public:Response(int result, int exitcode):result_(result),exitcode_(exitcode){}
public:int result_; // 计算结果int exitcode_; // 计算结果是否可靠
};//线程的执行流代码
void * SumThread(void * args){Request * Task = static_cast<Request *>(args);Response * Res = new Response(0,0);int begin = Task->start_;int end = Task->end_;for(int i = begin ; i <= end ; ++i){std :: cout << Task->threadname_ << " is runing, Summing..., " << i << std :: endl;Res->result_ += i; usleep(100000);}//注意使用完请求后释放请求结构体,防止内存泄漏delete Task;return static_cast<void *>(Res);
}int main()
{pthread_t tid;Request *rq = new Request(1, 100, "thread 1");//创建线程并传递计算任务请求pthread_create(&tid, nullptr, SumThread, rq);//用于接收Respond结构体地址void *ret;//pthread_join接口的ret参数用于获取线程函数的返回值,pthread_join接口默认执行阻塞等待pthread_join(tid, &ret);Response *rsp = static_cast<Response *>(ret);std :: cout << "rsp->result: " << rsp->result_ << ", exitcode: " << rsp->exitcode_ << std :: endl;delete rsp;return 0;
}