引入
本文旨在通过面向对象的方式,将 POSIX 线程(pthread)进行封装,提供一个简洁、安全、易用的 Thread 类接口。核心目标是:隐藏底层 pthread 的复杂性,暴露高层语义清晰的操作方法(如 Start()、Join()、Detach()、Stop())。
main
main.cc
cpp
#include "Thread.hpp"
#include <unistd.h>
#include <vector>
using namespace ThreadModlue;
int main()
{
// std::vector<Thread> threads;
// for (int i = 0; i < 10; i++)
// {
// threads.emplace_back([]()
// {
// while(true)
// {
// char name[128];
// pthread_getname_np(pthread_self(), name, sizeof(name));
// std::cout << "我是一个新线程: " << name << std::endl; // 我的线程的名字是什么呀?debug
// sleep(1);
// } });
// }
// for (auto &thread : threads)
// {
// thread.Start();
// }
// for (auto &thread : threads)
// {
// thread.Join();
// }
Thread t([](){
while(true)
{
char name[128];
pthread_getname_np(pthread_self(), name, sizeof(name));
std::cout << "我是一个新线程: " << name << std::endl; // 我的线程的名字是什么呀?debug
sleep(1);
}
});
t.Start();
t.Detach();
sleep(5);
t.Stop();
sleep(5);
t.Join();
return 0;
}
thread
thread.hpp
cpp
#ifndef _THREAD_H_
#define _THREAD_H_
#include <iostream>
#include <string>
#include <pthread.h>
#include <cstdio>
#include <cstring>
#include <functional>
namespace ThreadModlue
{
static uint32_t number = 1;
class Thread
{
using func_t = std::function<void()>;
private:
void EnableDetach()
{
std::cout << "线程被分离了" << std::endl;
_isdetach = true;
}
void EnableRunning()
{
_isrunning = true;
}
static void *Routine(void *args)
{
Thread *self = static_cast<Thread *>(args);
self->EnableRunning();
if (self->_isdetach)
self->Detach();
pthread_setname_np(self->_tid, self->_name.c_str());
self->_func();
return nullptr;
}
public:
Thread(func_t func)
: _tid(0),
_isdetach(false),
_isrunning(false),
res(nullptr),
_func(func)
{
_name = "thread-" + std::to_string(number++);
}
void Detach()
{
if (_isdetach)
return;
if (_isrunning)
pthread_detach(_tid);
EnableDetach();
}
bool Start()
{
if (_isrunning)
return false;
int n = pthread_create(&_tid, nullptr, Routine, this);
if (n != 0)
{
std::cerr << "create thread error: " << strerror(n) << std::endl;
return false;
}
else
{
std::cout << _name << " create success" << std::endl;
return true;
}
}
bool Stop()
{
if (_isrunning)
{
int n = pthread_cancel(_tid);
if (n != 0)
{
std::cerr << "cancel thread error: " << strerror(n) << std::endl;
return false;
}
else
{
_isrunning = false;
std::cout << _name << " stop" << std::endl;
return true;
}
}
return false;
}
void Join()
{
if (_isdetach)
{
std::cout << "你的线程已经是分离的了,不能进行join" << std::endl;
return;
}
int n = pthread_join(_tid, &res);
if (n != 0)
{
std::cerr << "create thread error: " << strerror(n) << std::endl;
}
else
{
std::cout << "join success" << std::endl;
}
}
~Thread()
{
}
private:
pthread_t _tid;
std::string _name;
bool _isdetach;
bool _isrunning;
void *res;
func_t _func;
};
}
#endif
makefile
makefile
shell
thread:main.cc
g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
rm -f thread
实验结果


解析
一、整体结构与核心设计思路
1. 代码框架
头文件保护宏 → 头文件引入 → 命名空间 → 静态全局变量 → Thread类定义(成员函数+成员变量)
- 命名空间 :
ThreadModlue用于隔离线程相关代码,避免命名冲突。 - 核心设计 :通过
std::function<void()>接收线程执行的任务(回调函数),把 pthread 的创建、分离、等待、取消等操作封装成类的成员函数,对外提供简洁的接口(Start/Stop/Join/Detach)。
2. 核心依赖
pthread.h:POSIX 线程库核心头文件,提供线程创建、管理的原生接口。std::function:C++11 特性,用于封装任意可调用对象(函数、lambda、函数对象等),作为线程的执行体,替代传统的函数指针,灵活性更高。
二、核心成员解析
1. 成员变量(私有)
| 变量名 | 类型 | 作用 |
|---|---|---|
_tid |
pthread_t |
线程 ID,唯一标识一个线程 |
_name |
std::string |
线程名称,格式为 thread-数字(数字由静态变量 number 自增生成) |
_isdetach |
bool |
标记线程是否为"分离态"(分离态线程无需手动 join,结束后自动释放资源) |
_isrunning |
bool |
标记线程是否正在运行 |
res |
void* |
存储线程退出时的返回值(pthread_join 的第二个参数) |
_func |
func_t |
线程要执行的任务(std::function<void()> 类型) |
2. 静态全局变量
cpp
static uint32_t number = 1; // bug(代码中标记的bug)
- 作用:为每个线程生成唯一的名称(thread-1、thread-2...)。
- 问题:
static修饰的全局变量属于编译单元(.o 文件)级别的静态,若这份头文件被多个 .cpp 包含,会生成多个独立的number实例,导致线程名称重复(正确做法应改为static uint32_t number = 1;放在类内,或用原子变量保证线程安全)。
3. 核心成员函数
(1)构造函数
cpp
Thread(func_t func)
: _tid(0), _isdetach(false), _isrunning(false), res(nullptr), _func(func)
{
_name = "thread-" + std::to_string(number++);
}
- 初始化线程的默认状态:非分离、未运行、线程 ID 为 0。
- 接收线程要执行的任务
func,并自动生成线程名称。
(2)线程启动:Start()
cpp
bool Start()
{
if (_isrunning) return false; // 防止重复启动
// 核心:调用 pthread_create 创建线程
int n = pthread_create(&_tid, nullptr, Routine, this);
if (n != 0) {
std::cerr << "create thread error: " << strerror(n) << std::endl;
return false;
} else {
std::cout << _name << " create success" << std::endl;
return true;
}
}
- 核心调用:
pthread_create(原生 pthread 线程创建接口)。 - 关键参数:
&_tid:输出线程 ID。nullptr:使用默认线程属性。Routine:线程的入口函数(必须是静态成员函数,因为 pthread 不支持非静态成员函数)。this:把当前 Thread 对象的指针传给 Routine,让静态函数能访问类的非静态成员。
(3)线程入口函数:Routine()(静态)
cpp
static void *Routine(void *args)
{
Thread *self = static_cast<Thread *>(args); // 转换为 Thread 对象指针
self->EnableRunning(); // 标记线程为运行状态
if (self->_isdetach) self->Detach(); // 如果设置了分离,执行分离操作
pthread_setname_np(self->_tid, self->_name.c_str()); // 设置线程名称
self->_func(); // 执行用户传入的任务
return nullptr;
}
- 为什么是静态函数?
非静态成员函数默认带this指针(隐藏参数),而pthread_create要求线程入口函数只能是void* (*)(void*)类型(无隐藏参数),因此必须用静态成员函数。 - 核心逻辑:把
void* args转回 Thread 对象指针,然后执行用户任务_func()。
一、先明确核心矛盾:pthread 的"硬性要求"
pthread 库是基于 C 语言实现的,C 语言没有"类"和"成员函数"的概念,所以 pthread_create(创建线程的核心函数)对线程入口函数有严格的签名要求:
cpp
// pthread_create 要求的入口函数类型
void* (*start_routine)(void*);
翻译一下这个要求:
- 函数的返回值必须是
void* - 函数的参数必须是且只能是一个
void* - 函数必须是普通函数(C 语言层面的函数,没有隐藏参数)
二、为什么非静态成员函数不行?
先看一个关键结论:C++ 的非静态成员函数,会被编译器偷偷加一个隐藏参数 this。
假设你把 Routine 写成非静态的:
cpp
// 你看到的代码
void* Routine(void* args) { ... }
// 编译器实际编译后的签名(伪代码)
void* Routine(Thread* this, void* args) { ... }
这个函数的参数变成了 2 个 (this + args),而不是 pthread 要求的 1 个 void* ,签名完全不匹配------pthread 库是 C 实现的,它不知道也无法处理这个隐藏的 this 指针,编译时会直接报错:
error: invalid conversion from 'void* (Thread::*)(void*)' to 'void* (*)(void*)'
三、为什么静态成员函数就可以?
静态成员函数的核心特性,刚好解决了上面的问题:
- 静态成员函数没有
this指针
- 静态成员函数属于类,而不是属于某个具体的对象
- 编译器不会给它加
this隐藏参数 - 它的签名可以完全符合 pthread 的要求:
void* (*)(void*)
- 静态函数如何访问对象的非静态成员?
静态函数本身不能直接访问_func、_isdetach等非静态成员(因为没有this),所以代码里做了一个关键操作:
cpp
static void *Routine(void *args)
{
// 把 pthread_create 传进来的 this 指针(Thread对象地址)转回来
Thread *self = static_cast<Thread *>(args);
// 有了 self(等价于 this),就能访问所有非静态成员了
self->EnableRunning();
self->_func();
...
}
(4)线程分离:Detach()
cpp
void Detach()
{
if (_isdetach) return; // 已分离则直接返回
if (_isrunning) pthread_detach(_tid); // 线程运行时执行分离
EnableDetach(); // 标记为分离态
}
- 分离态作用:线程结束后自动释放资源,无需调用
pthread_join。 - 注意:分离后的线程不能再调用
Join()。
(5)线程等待:Join()
cpp
void Join()
{
if (_isdetach) {
std::cout << "你的线程已经是分离的了,不能进行join" << std::endl;
return;
}
int n = pthread_join(_tid, &res); // 阻塞等待线程结束,获取返回值
if (n != 0) {
std::cerr << "create thread error: " << strerror(n) << std::endl;
} else {
std::cout << "join success" << std::endl;
}
}
- 核心调用:
pthread_join(阻塞等待线程退出,回收资源)。 - 限制:分离态线程无法 join,会直接提示错误。
(6)线程取消:Stop()
cpp
bool Stop()
{
if (_isrunning) {
int n = pthread_cancel(_tid); // 取消线程(向线程发送取消请求)
if (n != 0) {
std::cerr << "create thread error: " << strerror(n) << std::endl;
return false;
} else {
_isrunning = false;
std::cout << _name << " stop" << std::endl;
return true;
}
}
return false;
}
- 核心调用:
pthread_cancel(请求线程退出,并非立即终止,需线程到达"取消点"才会退出)。 - 注意:
pthread_cancel是"请求"而非"强制杀死",如果线程执行的任务中没有取消点(如循环无阻塞),线程可能不会退出。
(7)辅助函数(私有)
EnableDetach():设置_isdetach = true,标记线程为分离态。EnableRunning():设置_isrunning = true,标记线程为运行态。
完