【linux学习指南】模拟线程封装与智能指针shared_ptr
文章目录
- 📝线程封装
- 🌉 Thread.hpp
- 🌉 Makefile
- 🌠线程封装第一版
- 🌉 Makefile:
- 🌉Main.cc
- 🌉 Thread.hpp:
- 🌠线程封装第二版
- 🌉 Thread.hpp:
- 🌉 Main.cc
- 🌠单线程创建测试
- 🌉 Thread.hpp
- 🌉 main.cc
- 🌠智能指针std::shared_ptr
- 🚩总结
📝线程封装
🌉 Thread.hpp
// Thread.hpp
#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>
namespace ThreadModule
{
// 原⼦计数器,⽅便形成线程名称
std::uint32_t cnt = 0;
// 线程要执⾏的外部⽅法,我们不考虑传参,后续有std::bind 来进⾏类间耦合
using threadfunc_t = std::function<void()>;
// 线程状态
enum class TSTATUS
{
THREAD_NEW,
THREAD_RUNNING,
THREAD_STOP
};
// 线程
class Thread
{
private:
static void *run(void *obj)
{
Thread *self = static_cast<Thread *>(obj);
pthread_setname_np(pthread_self(), self->_name.c_str()); // 设置线程名称
self->_status = TSTATUS::THREAD_RUNNING;
if (!self->_joined)
{
pthread_detach(pthread_self());
}
self->_func();
return nullptr;
}
void SetName()
{
// 后期加锁保护
_name = "Thread-" + std::to_string(cnt++);
}
public:
Thread(threadfunc_t func) : _status(TSTATUS::THREAD_NEW),
_joined(true), _func(func)
{
SetName();
}
void EnableDetach()
{
if (_status == TSTATUS::THREAD_NEW)
_joined = false;
}
void EnableJoined()
{
if (_status == TSTATUS::THREAD_NEW)
_joined = true;
}
bool Start()
{
if (_status == TSTATUS::THREAD_RUNNING)
return true;
int n = ::pthread_create(&_id, nullptr, run, this);
if (n != 0)
return false;
return true;
}
bool Join()
{
if (_joined)
{
int n = pthread_join(_id, nullptr);
if (n != 0)
return false;
return true;
}
return false;
}
~Thread() {}
private:
std::string _name;
pthread_t _id;
TSTATUS _status;
bool _joined;
threadfunc_t _func;
};
}
🌉 Makefile
// main.cc
#include <iostream>
#include <unistd.h>
#include "Thread.hpp"
void hello1()
{
char buffer[64];
pthread_getname_np(pthread_self(), buffer, sizeof(buffer) - 1);
while (true)
{
}
std::cout << "hello world, " << buffer << std::endl;
sleep(1);
}
void hello2()
{
char buffer[64];
pthread_getname_np(pthread_self(), buffer, sizeof(buffer) - 1);
while (true)
{
std::cout << "hello world, " << buffer << std::endl;
sleep(1);
}
}
int main()
{
pthread_setname_np(pthread_self(), "main");
ThreadModule::Thread t1(hello1);
t1.Start();
ThreadModule::Thread t2(std::bind(&hello2));
t2.Start();
t1.Join();
t2.Join();
return 0;
}
运⾏结果查询
$ ps -aL
PID LWP TTY TIME CMD
195828 195828 pts/1 00:00:00 main
195828 195829 pts/1 00:00:00 Thread-0
195828 195830 pts/1 00:00:00 Thread-1
🌠线程封装第一版
🌉 Makefile:
bin=testThread
cc=g++
src=$(wildcard *.cc)
obj=$(src:.cc=.o)
$(bin):$(obj)
$(cc) -o $@ $^ -lpthread
%.o:%.cc
$(cc) -c $< -std=c++17
.PHONY:test
test:
echo $(src)
echo $(obj)
🌉Main.cc
#include "Thread.hpp"
#include <unordered_map>
#include <memory>
// using thread_ptr_t = std::shared_ptr<ThreadModule::Thread>;
#define NUM 10;
class threadData
{
public:
int max;
int start;
};
void Count(threadData td)
{
for(int i = td.start; i < td.max; i++)
{
std::cout<< "i == " <<i <<std::endl;
sleep(1);
}
}
int main()
{
threadData td;
td.max = 60;
td.start = 50;
//使用lamda表达式封装Count成一个不接受参数的可调用对象
auto func = [td]()
{
Count(td);
};
ThreadModule::Thread<threadData> t(func);
t.Start();
t.Join();
return 0;
}
🌉 Thread.hpp:
//V1
namespace ThreadModule
{
// template<typename T>
using func_t = std::function<void()>;
static int number = 1;
enum class TSTATUS
{
NEW,
RUNNING,
STOP
};
template<typename T>
class Thread
{
private:
static void* Routine(void *args)
{
Thread* t = static_cast<Thread *>(args);
t->_status = TSTATUS::RUNNING;
t->_func();
return nullptr;
}
void EnableDetach()
{
_joinable = false;
}
public:
Thread(func_t func)
: _func(func), _status(TSTATUS::NEW), _joinable(true)
{
_name = "Thread - " + std::to_string(number++);
_pid = getpid();
}
bool Start()
{
if (_status != TSTATUS::RUNNING)
{
int n = ::pthread_create(&_tid, nullptr, Routine, this); // 这里使用this
if (n != 0)
return false;
return true;
}
return true;
}
bool Stop()
{
if (_status != TSTATUS::RUNNING)
{
int n = ::pthread_cancel(_tid);
if (n != 0)
return false;
_status = TSTATUS::STOP;
return true;
}
return false;
}
bool Join()
{
if(_joinable)
{
int n = ::pthread_join(_tid, nullptr);
if(n != 0)
return false;
_status = TSTATUS::STOP;
return true;
}
return false;
}
void Detach()
{
EnableDetach();
pthread_detach(_tid);
}
bool IsJoinable()
{
return _joinable;
}
std::string Name()
{
return _name;
}
~Thread()
{
}
private:
std::string _name;
pthread_t _tid;
pid_t _pid;
bool _joinable; // 是否是分离的, 默认不是
func_t _func;
TSTATUS _status;
};
}
#endif
🌠线程封装第二版
🌉 Thread.hpp:
#ifndef THREAD_HPP
#define THREAD_HPP
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include <sys/types.h>
#include <unistd.h>
//V2
namespace ThreadModule
{
static int number = 1;
enum class TSTATUS
{
NEW,
RUNNING,
STOP
};
template<typename T>
class Thread
{
using func_t = std::function<void(T)>;
private:
//成员方法
static void *Routine(void* args)
{
Thread<T> *t = static_cast<Thread<T>*>(args);
t->_status = TSTATUS::RUNNING;
t->_func(t->_data);
return nullptr;
}
void EnableDetach()
{
_joinable = false;
}
public:
Thread(func_t func, T data)
:_func(func)
,_data(data)
,_status(TSTATUS::NEW)
,_joinable(true)
{
_name = "Thread -" +std::to_string(number++);
_pid = getpid();
}
bool Start()
{
if(_status != TSTATUS::RUNNING)
{
int n = pthread_create(&_tid, nullptr, Routine, this);
if(n != 0)
return false;
return true;
}
return false;
}
bool Stop()
{
if(_status == TSTATUS::RUNNING)
{
int n = ::pthread_cancel(_tid);
if(n != 0)
return false;
_status = TSTATUS::STOP;
return true;
}
return false;
}
bool Join()
{
if(_joinable)
{
int n = ::pthread_join(_tid, nullptr);
if(n != 0)
return false;
_status = TSTATUS::STOP;
return true;
}
return false;
}
bool IsJoinale()
{
return _joinable;
}
std::string Name()
{
return _name;
}
~Thread()
{
}
private:
std::string _name;
pthread_t _tid;
bool _joinable;//是否是分离的,默认不是
func_t _func;
pid_t _pid;
TSTATUS _status;
T _data;
};
}
#endif
🌉 Main.cc
#include "Thread.hpp"
#include <unordered_map>
#include <memory>
using thread_ptr_t = std::shared_ptr<ThreadModule::Thread<int>>;
#define NUM 10
class threadData
{
public:
int max;
int start;
};
void Count(threadData td)
{
for(int i = td.start; i < td.max; i++)
{
std::cout<< "i == " <<i <<std::endl;
sleep(1);
}
}
int main()
{
//先描述再组织
std::unordered_map<std::string, thread_ptr_t> threads;
//如果我们要创建多线程呢?
for(int i = 0; i< NUM ; i++)
{
auto func = []()
{
while(true)
{
std::cout<< "hello world" << std::endl;
sleep(1);
}
};
int threadData = i+1;
thread_ptr_t t= std::make_shared<ThreadModule::Thread<int>>(
[func](int)
{
func();
},
threadData
);
std::cout<< "Create thread with name : "<<t->Name() <<std::endl;
threads[t->Name()] = t;
}
for(auto &thread : threads)
{
thread.second->Start();
}
for(auto &thread : threads)
{
thread.second->Join();
}
🌠单线程创建测试
🌉 Thread.hpp
#ifndef THREAD_HPP
#define THREAD_HPP
#include <iostream>
#include <string>
#include <pthread.h>
#include <functional>
#include <sys/types.h>
#include <unistd.h>
//V2
namespace ThreadModule
{
static int number = 1;
enum class TSTATUS
{
NEW,
RUNNING,
STOP
};
template<typename T>
class Thread
{
using func_t = std::function<void(T)>;
private:
//成员方法
static void *Routine(void* args)
{
Thread<T> *t = static_cast<Thread<T>*>(args);
t->_status = TSTATUS::RUNNING;
t->_func(t->_data);
return nullptr;
}
void EnableDetach()
{
_joinable = false;
}
public:
Thread(func_t func, T data)
:_func(func)
,_data(data)
,_status(TSTATUS::NEW)
,_joinable(true)
{
_name = "Thread -" +std::to_string(number++);
_pid = getpid();
}
bool Start()
{
if(_status != TSTATUS::RUNNING)
{
int n = pthread_create(&_tid, nullptr, Routine, this);
if(n != 0)
return false;
return true;
}
return false;
}
bool Stop()
{
if(_status == TSTATUS::RUNNING)
{
int n = ::pthread_cancel(_tid);
if(n != 0)
return false;
_status = TSTATUS::STOP;
return true;
}
return false;
}
bool Join()
{
if(_joinable)
{
int n = ::pthread_join(_tid, nullptr);
if(n != 0)
return false;
_status = TSTATUS::STOP;
return true;
}
return false;
}
bool IsJoinale()
{
return _joinable;
}
std::string Name()
{
return _name;
}
~Thread()
{
}
private:
std::string _name;
pthread_t _tid;
bool _joinable;//是否是分离的,默认不是
func_t _func;
pid_t _pid;
TSTATUS _status;
T _data;
};
}
🌉 main.cc
#include "Thread.hpp"
#include <unordered_map>
#include <memory>
using thread_ptr_t = std::shared_ptr<ThreadModule::Thread<int>>;
#define NUM 10
class threadData
{
public:
int max;
int start;
};
void Count(threadData td)
{
for(int i = td.start; i < td.max; i++)
{
std::cout<< "i == " <<i <<std::endl;
sleep(1);
}
}
int main()
{
auto func = []()
{
while(true)
{
std::cout<< "hello world" <<std::endl;
sleep(1);
}
};
std::function<void(int)> wrappedFunc2 = [func](int){ func(); };
int signalTreadData = 5;
ThreadModule::Thread<int> t( wrappedFunc2,
signalTreadData);
// std::cout<< "Create thread with name : "<<t->Name() <<std::endl;
// t.Start();
// t.Join();
t.Start();
std::cout<< t.Name() << " is running" <<std::endl;
std::cout<<std::flush;//手动刷新缓冲期
sleep(5);
if (t.Stop()) {
std::cout << "Stop thread : " << t.Name() << std::endl;
std::cout << std::flush; // 手动刷新缓冲区
} else {
std::cout << "Failed to stop thread : " << t.Name() << std::endl;
std::cout << std::flush; // 手动刷新缓冲区
}
sleep(1);
if (t.Join()) {
std::cout << "Join thread : " << t.Name() << std::endl;
std::cout << std::flush; // 手动刷新缓冲区
} else {
std::cout << "Failed to join thread : " << t.Name() << std::endl;
std::cout << std::flush; // 手动刷新缓冲区
}
return 0;
}
🌠智能指针std::shared_ptr
std::shared_ptr
是 C++ 标准库 <memory>
头文件中提供的一种智能指针,用于管理动态分配的对象,它实现了共享所有权的语义,下面为你详细介绍它的作用、工作原理以及在你给出的代码中的使用场景。
作用
在传统的 C++ 中,使用 new
操作符动态分配内存后,需要手动使用 delete
操作符释放内存,否则会导致内存泄漏。std::shared_ptr
可以自动管理动态分配的对象的生命周期,当没有任何 std::shared_ptr
指向该对象时,它会自动释放对象所占用的内存,从而避免了手动管理内存带来的复杂性和潜在的内存泄漏问题。
工作原理
std::shared_ptr
使用引用计数的机制来管理对象的生命周期。每个 std::shared_ptr
都维护一个引用计数,记录有多少个 std::shared_ptr
共享同一个对象。当一个新的 std::shared_ptr
指向一个对象时,引用计数加 1;当一个 std::shared_ptr
被销毁或者指向其他对象时,引用计数减 1。当引用计数变为 0 时,说明没有任何 std::shared_ptr
再指向该对象,此时 std::shared_ptr
会自动调用对象的析构函数并释放内存。
-
using thread_ptr_t = std::shared_ptr<ThreadModule::Thread<int>>;
这行代码使用using
关键字定义了一个类型别名thread_ptr_t
,它实际上是std::shared_ptr<ThreadModule::Thread<int>>
的别名。这样做的好处是可以简化代码,避免在后续使用时多次书写冗长的类型名。这里的ThreadModule::Thread<int>
是一个模板类的实例化,表示一个线程对象,std::shared_ptr
用于管理这个线程对象的生命周期。 -
std::unordered_map<std::string, thread_ptr_t> threads;
这行代码定义了一个std::unordered_map
,它是一个无序关联容器,用于存储键值对。键的类型是std::string
,值的类型是thread_ptr_t
,也就是std::shared_ptr<ThreadModule::Thread<int>>
。通过这种方式,可以将线程对象与一个字符串键关联起来,方便对线程对象进行管理和查找。 -
thread_ptr_t t = std::make_shared<ThreadModule::Thread<int>>( ... );
这行代码使用std::make_shared
函数创建了一个std::shared_ptr<ThreadModule::Thread<int>>
对象,并将其赋值给t
。std::make_shared
是一个便捷的函数,用于创建std::shared_ptr
对象,它会在一次内存分配中同时分配对象和引用计数所需的内存,比分别使用new
和std::shared_ptr
的构造函数更加高效。括号内的参数是传递给ThreadModule::Thread<int>
构造函数的参数,用于初始化线程对象。
示例代码
#include <iostream>
#include <memory>
class MyClass {
public:
MyClass() { std::cout << "MyClass constructor" << std::endl; }
~MyClass() { std::cout << "MyClass destructor" << std::endl; }
void doSomething() { std::cout << "Doing something..." << std::endl; }
};
int main() {
// 创建一个 std::shared_ptr 对象
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
// 复制一个 std::shared_ptr 对象,引用计数加 1
std::shared_ptr<MyClass> ptr2 = ptr1;
// 调用对象的成员函数
ptr1->doSomething();
// 当 ptr1 和 ptr2 离开作用域时,引用计数减 1
// 当引用计数变为 0 时,对象会被自动销毁
return 0;
}
代码解释
- 在
main
函数中,首先使用std::make_shared
创建了一个std::shared_ptr<MyClass>
对象ptr1
,此时引用计数为 1。 - 然后将
ptr1
赋值给ptr2
,引用计数变为 2。 - 调用
ptr1->doSomething()
来调用对象的成员函数。 - 当
ptr1
和ptr2
离开main
函数的作用域时,它们会被销毁,引用计数减 1。当引用计数变为 0 时,MyClass
对象的析构函数会被自动调用,释放对象所占用的内存。
🚩总结
如果要像C++11那样进⾏可变参数的传递,是可以这样设计的,但是太⿇烦了,真到了哪⼀步,就直接⽤c++11吧,我们的⽬标主要是理解系统概念对象化,此处不做复杂设计,⽽且后续可以使⽤std::bind来进⾏对象间调⽤