【linux学习指南】模拟线程封装与智能指针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 会自动调用对象的析构函数并释放内存。

  1. 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 用于管理这个线程对象的生命周期。

  2. std::unordered_map<std::string, thread_ptr_t> threads;

    这行代码定义了一个 std::unordered_map,它是一个无序关联容器,用于存储键值对。键的类型是 std::string,值的类型是 thread_ptr_t,也就是 std::shared_ptr<ThreadModule::Thread<int>>。通过这种方式,可以将线程对象与一个字符串键关联起来,方便对线程对象进行管理和查找。

  3. thread_ptr_t t = std::make_shared<ThreadModule::Thread<int>>( ... );

    这行代码使用 std::make_shared 函数创建了一个 std::shared_ptr<ThreadModule::Thread<int>> 对象,并将其赋值给 tstd::make_shared 是一个便捷的函数,用于创建 std::shared_ptr 对象,它会在一次内存分配中同时分配对象和引用计数所需的内存,比分别使用 newstd::shared_ptr 的构造函数更加高效。括号内的参数是传递给 ThreadModule::Thread<int> 构造函数的参数,用于初始化线程对象。

示例代码

cpp 复制代码
#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() 来调用对象的成员函数。
  • ptr1ptr2 离开 main 函数的作用域时,它们会被销毁,引用计数减 1。当引用计数变为 0 时,MyClass 对象的析构函数会被自动调用,释放对象所占用的内存。

🚩总结

如果要像C++11那样进⾏可变参数的传递,是可以这样设计的,但是太⿇烦了,真到了哪⼀步,就直接⽤c++11吧,我们的⽬标主要是理解系统概念对象化,此处不做复杂设计,⽽且后续可以使⽤std::bind来进⾏对象间调⽤

相关推荐
周湘zx6 分钟前
nginx不在默认的yum仓库的解决方法
运维·python·nginx
tonngw9 分钟前
Docker 使用指南
运维·docker·容器
年轮不改1 小时前
Ubuntu 配置 ffmpeg 开发环境
linux·ubuntu·ffmpeg
编程小小白白1 小时前
Jetson Orin NX jupyter lab的安装和使用
linux·ubuntu·jupyter
高高山上立1 小时前
【组件安装】Ubuntu 22.04.5 desktop 安装 Anyware Agent
ubuntu·hp anyware
乙龙1 小时前
在麒麟系统(基于Ubuntu或Debuntu)的离线环境中创建本地APT仓库
linux·运维·ubuntu·kylin
舰长1152 小时前
Ubuntu docker安装milvusdb
linux·运维·服务器
niuTaylor2 小时前
Linux驱动开发实战之PCIE驱动(一)
linux·运维·驱动开发
云动雨颤2 小时前
Xshell7连接Debian12系统,中文显示乱码,解决办法一览!
运维·debian