hello~ 很高兴见到大家! 这次带来的是Linux系统中关于线程这部分的一些知识点,如果对你有所帮助的话,可否留下你宝贵的三连呢?
个 人 主 页 : 默|笙

文章目录
一、代码实现
- 下面是 thread.hpp 文件代码,是对 一些 pthread 函数的封装操作:
cpp
#pragma once
#include <pthread.h>
#include <functional>
#include <iostream>
namespace ThreadMoudle
{
int gnumber = 1;
using callback_t = std::function<void()>;
enum class TSTATUS
{
THREAD_NEW,
THREAD_RUNNING,
THREAD_STOP
};
std::string IsJoined(bool joinable)
{
return joinable ? "Joinable" : "Detached";
}
std::string Status2String(TSTATUS s)
{
switch (s)
{
case TSTATUS::THREAD_NEW:
return "THREAD_NEW";
case TSTATUS::THREAD_RUNNING:
return "THREAD_RUNNING";
case TSTATUS::THREAD_STOP:
return "THREAD_STOP";
default:
return "UNKNOWN";
}
}
class Thread
{
private:
void ToRunning()
{
_status = TSTATUS::THREAD_RUNNING;
}
void ToStop()
{
_status = TSTATUS::THREAD_STOP;
}
//线程要执行的函数,必须加上static,不加第一个参数会是this指针
static void *Routine(void *args)
{
Thread *it = static_cast<Thread*>(args);
//线程要执行的任务
it->_ct();
pthread_setname_np(it->_tid, it->_name.c_str());
it->ToStop();
return nullptr;
}
public:
Thread(callback_t ct)
: _tid(-1), _status(TSTATUS::THREAD_NEW), _ct(ct), _joinable(true), _result(nullptr)
{
_name = "New-Thread-" + std::to_string(gnumber++);
}
bool Start()
{
//把this传递给要执行的函数
int n = pthread_create(&_tid, nullptr, Routine, this);
ToRunning();
if (n != 0)
return false;
return true;
}
void Join()
{
if (_joinable)
{
int n = pthread_join(_tid, &_result);
if (n != 0)
{
std::cerr << "join error:" << n << std::endl;
return;
}
(void)_result;
ToStop();
}
else
{
std::cerr << "join error, joinable: " << IsJoined(_joinable) << std::endl;
}
}
void Die()
{
if (_status == TSTATUS::THREAD_RUNNING)
{
pthread_cancel(_tid);
ToStop();
}
}
void Detach()
{
if (_joinable)
{
pthread_detach(_tid);
_joinable = false;
}
else
{
std::cerr << "detach " << _name << "failed" << std::endl;
}
}
~Thread()
{
}
void Print()
{
std::cout << "_name: " << _name << std::endl;
std::cout << "tid: " << _tid << std::endl;
std::cout << "status: " << Status2String(_status) << std::endl;
std::cout << "joinable: " << IsJoined(_joinable) << std::endl;
}
private:
std::string _name;//线程名字
pthread_t _tid;//线程id
TSTATUS _status;//线程的执行状态
callback_t _ct;//线程要执行的任务
bool _joinable;//线程是否可以被等待
void* _result;//线程的返回值
};
}
- 之所以 Routine 函数必须声明为静态(加上 static),是因为如果不加 static,它就属于类的非静态成员函数,会隐式携带 this 指针作为第一个参数,导致函数签名与 pthread_create 要求的线程入口函数格式不匹配。pthread_create 要求线程入口函数必须是无 this 指针、参数为单个 void*、返回值为 void* 的普通函数指针格式。而我们后续访问类的非静态私有成员时又必须用到 this 指针,因此在调用 pthread_create 时,就把当前对象的 this 指针以 void* 类型作为参数传递给这个静态 Routine 函数,再在函数内部还原出对象指针,从而正常访问类成员。
二、解决传参问题
1.1 使用模板
- 可以使用模板来解决传参问题,下面是使用单个模板参数解决传递单参数的方法,如果要传递多参数可以使用可变参数模板。要修改 thread.hpp 文件。
cpp
#pragma once
#include <pthread.h>
#include <functional>
#include <iostream>
namespace ThreadMoudle
{
int gnumber = 1;
template<typename T>
using callback_t = std::function<void(T&)>;
enum class TSTATUS
{
THREAD_NEW,
THREAD_RUNNING,
THREAD_STOP
};
std::string IsJoined(bool joinable)
{
return joinable ? "Joinable" : "Detached";
}
std::string Status2String(TSTATUS s)
{
switch (s)
{
case TSTATUS::THREAD_NEW:
return "THREAD_NEW";
case TSTATUS::THREAD_RUNNING:
return "THREAD_RUNNING";
case TSTATUS::THREAD_STOP:
return "THREAD_STOP";
default:
return "UNKNOWN";
}
}
template<typename T>
class Thread
{
private:
void ToRunning()
{
_status = TSTATUS::THREAD_RUNNING;
}
void ToStop()
{
_status = TSTATUS::THREAD_STOP;
}
//线程要执行的函数,必须加上static,不加第一个参数会是this指针
static void *Routine(void *args)
{
Thread *it = static_cast<Thread<T>*>(args);
//线程要执行的任务
it->_ct(it->_data);
pthread_setname_np(it->_tid, it->_name.c_str());
it->ToStop();
return nullptr;
}
public:
Thread(callback_t<T> ct, const T& data)
: _tid(-1)
, _status(TSTATUS::THREAD_NEW)
, _ct(ct)
, _joinable(true)
, _result(nullptr)
, _data(data)
{
_name = "New-Thread-" + std::to_string(gnumber++);
}
bool Start()
{
//把this传递给要执行的函数
int n = pthread_create(&_tid, nullptr, Routine, this);
ToRunning();
if (n != 0)
return false;
return true;
}
void Join()
{
if (_joinable)
{
int n = pthread_join(_tid, &_result);
if (n != 0)
{
std::cerr << "join error:" << n << std::endl;
return;
}
(void)_result;
ToStop();
}
else
{
std::cerr << "join error, joinable: " << IsJoined(_joinable) << std::endl;
}
}
void Die()
{
if (_status == TSTATUS::THREAD_RUNNING)
{
pthread_cancel(_tid);
ToStop();
}
}
void Detach()
{
if (_joinable)
{
pthread_detach(_tid);
_joinable = false;
}
else
{
std::cerr << "detach " << _name << "failed" << std::endl;
}
}
~Thread()
{
}
void Print()
{
std::cout << "_name: " << _name << std::endl;
std::cout << "tid: " << _tid << std::endl;
std::cout << "status: " << Status2String(_status) << std::endl;
std::cout << "joinable: " << IsJoined(_joinable) << std::endl;
}
private:
std::string _name;//线程名字
pthread_t _tid;//线程id
TSTATUS _status;//线程的执行状态
callback_t<T> _ct;//线程要执行的任务
bool _joinable;//线程是否可以被等待
void* _result;//线程的返回值
T _data;
};
}
1.2 使用类和lambda表达式
- 我们可以把任务和它所涉及的一些变量打包成一个类,然后通过传递无参无返回值的lambda表达式(匿名函数对象)给目标线程,从而实现传递多个参数。这样就不用修改我们封装的 thread.hpp 文件了。
cpp
#include <iostream>
#include "Thread.hpp"
#include <unistd.h>
#include <vector>
class Task
{
public:
Task(int x, int y) : _x(x), _y(y)
{}
void Execute()
{
_result = _x + _y;
}
void Print()
{
std::cout << _x << " + " << _y << " = " << _result << std::endl;
}
~Task()
{}
private:
int _x;
int _y;
int _result;
};
int main()
{
Task tk(12, 20);
ThreadMoudle::Thread thread([&tk](){tk.Execute();});
thread.Start();
thread.Join();
thread.Print();
sleep(5);
tk.Print();
return 0;
}
今天的分享就到此结束啦,如果对读者朋友们有所帮助的话,可否留下宝贵的三连呢~~
让我们共同努力, 一起走下去!