目录
[1 创建线程](#1 创建线程)
[1.1 pthread_create](#1.1 pthread_create)
[2.2 pthread_self](#2.2 pthread_self)
[2 线程等待](#2 线程等待)
[2.1 pthread_join](#2.1 pthread_join)
[3 线程终止](#3 线程终止)
[3.1 pthread_exit](#3.1 pthread_exit)
[3.2 pthread_cancel](#3.2 pthread_cancel)
[4 线程分离](#4 线程分离)
[4.1 pthread_detach](#4.1 pthread_detach)
[5 POSIX库](#5 POSIX库)
[5.1 线程ID及进程地址空间布局](#5.1 线程ID及进程地址空间布局)
1 创建线程
1.1 pthread_create
(1)功能
pthread_create 是 POSIX 线程(pthread)库中用于创建新线程的函数,它是 Linux 和其他类 Unix 系统中多线程编程的基础。
(2)函数原型
cpp
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
(3)函数参数
- thread(输出型参数)
- 指向 pthread_t 类型的指针,用于存储新线程的标识符
- 线程创建成功后,系统会将线程ID写入这个位置
- attr
- 指向线程属性对象的指针,用于设置线程属性(如栈大小、调度策略等)
- 如果为 NULL,则使用默认属性
- start_routine
- 线程启动后执行的函数指针
- 函数形式应为:void *func_name(void *arg)
- arg
- 传递给 start_routine 的参数
- 如果需要传递多个参数,可以封装在结构体中
(4)返回值
- 成功:返回 0
- 失败 :返回错误代码(不是设置 errno)
(5)示例
cpp
#include <iostream>
#include <unistd.h>
#include <pthread.h>
// 线程执行入口
void* thread_func(void* args)
{
std::string str = (char*)args;
// 第二个循环
while(true)
{
printf("Second thread:%s pid:%d num:%d\n", str.c_str(), getpid(), num);
sleep(1);
}
}
int main()
{
pthread_t tid;
// 创建线程
pthread_create(&tid, nullptr, thread_func, (void*)"pthread-1");
// 主线程
// 第一个循环
while(true)
{
printf("Main thread pid:%d num:%d\n", getpid(), num);
sleep(1);
}
return 0;
}
2.2 pthread_self
(1)功能
pthread_self 是 POSIX 线程库中用于获取调用线程自身轻量级进程PID的函数
(2)函数原型
cpp
#include <pthread.h>
pthread_t pthread_self(void);
(3)返回值
- 返回调用线程的线程标识符(pthread_t 类型)
2 线程等待
如果主线程结束,就代表整个进程结束了,进程结束,所有线程全部退出,哪怕没有执行完,因此在多线程中,主线程应该是最后退出的
为什么需要线程等待?
- 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
- 创建新的线程不会复⽤刚才退出线程的地址空间
2.1 pthread_join
(1)功能
pthread_join 是 POSIX 线程(pthread)库中用于等待指定线程终止并回收其资源的函数
(2)函数原型
cpp
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
(3)函数参数
- thread
- 要等待的线程标识符(由 pthread_create 返回的 pthread_t 类型)
- retval
- 指向指针的指针,用于存储目标线程的返回值
- 如果不关心返回值,可以设置为 NULL
- 目标线程的返回值通过 pthread_exit() 或 return 语句返回
(4)返回值
- 成功:返回 0
- 失败 :返回错误代码(不是设置 errno)
(5)示例
cpp
// 线程执行入口
void* thread_func(void* args)
{
std::string str = (char*)args;
int cnt = 5;
// 第二个循环
while(cnt--)
{
printf("New thread:%s\n", str.c_str());
sleep(1);
}
// 返回一个整数
return (void*)10;
}
int main()
{
// 线程名字
const char* name = "thread-1";
pthread_t tid;
// 创建线程
int pid = pthread_create(&tid, nullptr, thread_func, (void*)name);
// 主线程
// 等待线程
// 记录退出信息
void* ret = nullptr;
int n = pthread_join(tid, &ret);
// 不需要考虑线程异常问题,因为没机会处理
printf("wait 0x%p succeed, thread exit information:%lld\n", (void*)tid, (long long)ret);
return 0;
}
(6)应用层面传参和返回值
cpp
// 模拟一个简单的线程任务类
class Task
{
public:
Task(int x = 0, int y = 0, int result = 0, int exitCode = 0)
:_x(x)
,_y(y)
,_result(result)
,_exitCode(exitCode)
{}
void Div()
{
if(_y == 0)
{
// 出现错误,设置错误码
_exitCode = 1;
return;
}
_result = _x / _y;
}
void Print()
{
std::cout<<"result:"<<_result<<" exitCode:"<<_exitCode<<std::endl;
}
private:
int _x;
int _y;
int _result;
int _exitCode;
};
// 线程执行入口
void* thread_func(void* args)
{
// 接收任务类
Task* task = (Task*)args;
task->Div();
// 返回任务类
return (void*)task;
}
int main()
{
// 线程名字
const char* name = "thread-1";
// 创建任务类
Task* task = new Task(20, 0);
pthread_t tid;
// 创建线程,传递任务
int pid = pthread_create(&tid, nullptr, thread_func, (void*)task);
// 主线程
// 等待线程
// 记录退出信息
void* ret = nullptr;
int n = pthread_join(tid, &ret);
task = (Task*)ret;
task->Print();
// 不需要考虑线程异常问题,因为没机会处理
printf("wait 0x%p succeed, thread exit information:%lld\n", (void*)tid, (long long)ret);
return 0;
}
3 线程终止
如果需要只终⽌某个线程⽽不终⽌整个进程,可以有三种⽅法:
- 从线程函数return。(这种⽅法对主线程不适⽤,从main函数return相当于调⽤exit)
- 线程可以调⽤pthread_ exit终⽌⾃⼰。
- ⼀个线程可以调⽤pthread_ cancel终⽌同⼀进程中的另⼀个线程。
3.1 pthread_exit
(1)功能
pthread_exit 是 POSIX 线程库中用于显式终止调用线程的函数,它允许线程在结束执行时返回一个值给其他等待它的线程。
(2)函数原型
cpp
#include <pthread.h>
void pthread_exit(void *retval);
(3)函数参数
- retval
- 线程的退出状态值,可以被其他线程通过 pthread_join 获取
- 可以传递任何类型的指针,但接收方需要知道如何解析
- 如果不需要返回值,可以设为 NULL
3.2 pthread_cancel
(1)功能
pthread_cancel 是 POSIX 线程库中用于请求取消(终止)另一个线程的函数。它提供了一种异步终止线程的机制。
(2)函数原型
cpp
#include <pthread.h>
int pthread_cancel(pthread_t thread);
(3)函数参数
- thread
- 要取消的目标线程的标识符(由 pthread_create 返回的 pthread_t 类型)
(4)返回值
- 成功:返回 0
- 失败 :返回错误代码(不是设置 errno)
4 线程分离
默认情况下,新创建的线程是joinable的,线程退出后,需要对其进⾏pthread_join操作,否则⽆法释放资源,从⽽造成系统泄漏
如果不关心线程的返回值,join是⼀种负担,这个时候,我们可以告诉系统,当线程退出时,⾃动释放线程资源
4.1 pthread_detach
(1)功能
pthread_detach 是 POSIX 线程库中用于将线程标记为"分离状态"(detached state)的函数,使线程终止时能够自动释放资源,无需其他线程调用 pthread_join。
(2)函数原型
cpp
#include <pthread.h>
int pthread_detach(pthread_t thread);
(3)函数参数
- thread
- 要设置为分离状态的线程标识符(由 pthread_create 返回的 pthread_t 类型)
(4)返回值
- 成功:返回 0
- 失败 :返回错误代码(不是设置 errno)
(5)示例
cpp
// 线程执行入口
void* thread_func(void* args)
{
// 线程主动分离
pthread_detach(pthread_self());
std::string str = (char*)args;
// 返回
return (void*)10;
}
int main()
{
// 线程名字
const char* name = "thread-1";
pthread_t tid;
// 创建线程,传递任务
int pid = pthread_create(&tid, nullptr, thread_func, (void*)name);
// 主进程分离指定线程
pthread_detach(tid);
sleep(1);
// 主线程
// 等待线程
// 记录退出信息
void* ret = nullptr;
int n = pthread_join(tid, &ret);
// 不需要考虑线程异常问题,因为没机会处理
printf("wait 0x%p succeed, thread exit information:%lld, code:%d\n", (void*)tid, (long long)ret, n);
return 0;
}
5 POSIX库
与线程有关的函数构成了⼀个完整的系列,绝⼤多数函数的名字都是以"pthread_"打头的,要使⽤这些函数库,要通过引⼊头文件
链接这些线程函数库时要使⽤编译器命令的"-lpthread"选项 ,因为头文件 不属于C标准库,属于Linux系统的原生库,也就是第三方库
5.1 线程ID及进程地址空间布局
pthread_ create函数会产⽣⼀个线程ID,存放在第⼀个参数指向的地址中。该线程ID和前⾯说的线程ID不是⼀回事。前⾯讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最⼩单位,所以需要⼀个数值来唯⼀表⽰该线程。
pthread_ create函数第⼀个参数指向⼀个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库(pthread库)的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
问题:thread_t 到底是什么类型呢?
取决于实现。对于Linux⽬前实现的NPTL实现⽽⾔,pthread_t类型的线程ID,本质就是⼀个进程地址空间上的⼀个地址。线程库(pthread)中创建的TCB结构体的起始地址

