thread.hpp
cpp
#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <pthread.h>
namespace ThreadModule
{
static uint32_t number = 1; // 第几个创建的线程
using func_t = std::function<void()>; // 包装器
class Thread
{
private:
void EnableDetach()
{
_isDetach = true;
}
void EnableRunning()
{
_isRunning = true;
}
// void* Routine(Thread* this,void* args)
// 静态成员函数,参数不带this指针
static void *Routine(void *args)
{
//std::cout << "Routine" << std::endl;
Thread *self = static_cast<Thread *>(args);
self->_isRunning = true;
// 如果设置为分离,调用pthread_datach结束后自动回收线程
if (self->_isDetach)
self->Detach();
// 设置线程名
pthread_setname_np(self->_tid, self->_name.c_str());
// 回调函数,执行线程任务
self->_func();
return nullptr;
}
public:
Thread(func_t func)
: _tid(pthread_self()),
_isDetach(false),
_isRunning(false),
_res(nullptr),
_func(func)
{
_name = "thread-" + std::to_string(number++);
}
// 开始线程
bool Start()
{
if (_isRunning) // 二次运行
return false;
int n = pthread_create(&_tid, NULL, Routine, this);
if (n == 0)
{
std::cout << "线程创建成功..." << std::endl;
return true;
}
else
{
std::cerr << "线程创建失败..." << strerror(n) << std::endl;
return false;
}
EnableRunning();
}
// 分离线程,使用 pthread_datach,线程结束后自动回收
void Detach()
{
if (_isDetach)
return;
// 分离、更新状态
if (_isRunning)
pthread_detach(_tid);
EnableDetach();
}
// 停止线程
bool Stop()
{
if (_isRunning)
{
// 取消一个正在执行的线程
int n = pthread_cancel(_tid);
if (n == 0)
{
std::cout << _name << ",stop success!" << std::endl;
return true;
}
else
{
std::cerr << "线程取消失败:" << strerror(n) << std::endl;
return false;
}
}
return false;
}
// 收回线程
void Join()
{
// 已经分离的线程不能手动回收
if (_isDetach)
{
std::cout << "线程已经是分离的的了,不能再join" << std::endl;
return;
}
int n = pthread_join(_tid, &_res);
if (n == 0)
{
std::cout << "join success..." << std::endl;
}
else
{
std::cerr << "join error..." << strerror(n) << std::endl;
}
}
~Thread()
{
}
private:
pthread_t _tid;
std::string _name;
bool _isDetach; // 线程是否分离
bool _isRunning; // 线程是否运行
void *_res; // pthread_join(&tid,res); res是输出型参数,保存线程的退出返回值
func_t _func; // 回调函数
};
}
成员变量:
- 线程 id
- 自定义线程名
- 是否分离标志位
- 是否运行标志位
- 输出形参数res,pthread_join(&tid,res),线程的退出状 态
- 线程调用函数
- Start 函数:如果还未运行,调用 pthread_create 设置线程的调用函数,并传入 this 指针。
- Routine 函数:线程的调用函数,必须是静态成员函数(static),因为 C++普通的成员函数第一个参数是一个隐式的 this 指针。static函数不带。Routine函数最后会回调 func 函数,即线程会调用func 函数
- Detach 函数:调用 pthread_detach 函数,线程结束后自动回收。
- Join 函数:调用 pthread_join 函数,手动回收线程。
- Stop 函数:调用pthread_cancel 函数,取消一个正在执行的线程。
Main.cc
cpp
#include <iostream>
#include <unistd.h>
#include <vector>
#include "Thread.hpp"
using namespace ThreadModule;
void func()
{
while (true)
{
// 获取线程名
char name[1024];
pthread_getname_np(pthread_self(), name, sizeof(name));
std::cout << "我是一个新线程:" << name << std::endl;
sleep(1);
}
}
int main()
{
// 创建10个子进程,使用vector存储
std::vector<Thread> td;
for (int i = 0; i < 10; i++)
{
//td.emplace_back(Thread(func()));// func()是函数调用,不是传参
//td.emplace_back(Thread(func));// 显示插入
//td.emplace_back(func);// 隐式转换
// Lambada表达式
// Lambda表达式
// ↓ (隐式转换)
// std::function<void()> (即 func_t)
// ↓ (匹配Thread构造函数)
// Thread(func_t func)
// ↓ (emplace_back在vector内部构造)
// Thread对象
td.emplace_back([]()
{
while(true)
{
// 获取线程名
char name[1024];
pthread_getname_np(pthread_self(),name,sizeof(name));
std::cout<<"我是一个新线程:"<<name<<std::endl;
sleep(1);
} });
}
// 开始+回收线程
for (auto &thread : td)
{
// Start负责创建线程,设置调用函数,调用Rouine,Rouine内部回调func
thread.Start();
}
for (auto &thread : td)
{
thread.Join();
}
return 0;
}
使用 vector 管理线程。
插入线程的流程是:
- 使用 emplace_back 向 vector 中插入元素,我们这边插入的是 Lambda 表达式,即插入一个 void() 函数。
- Lambda 表达式隐式转换->std::function<void()> (即 func_t),func_t 类型与 Thread 的构造函数匹配,于是就创建了一个 Thread 对象。
插入 Thread 对象时,不能这样插入:td.emplace_back(Thread(func())); 因为func()是函数调用,不是传参。可以 td.emplace_back(Thread(func)); 显示传参,也可以 td.emplace_back(func); 走隐式类型转换。