当前位置: 首页 > article >正文

【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 会自动调用对象的析构函数并释放内存。

  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> 构造函数的参数,用于初始化线程对象。

示例代码

#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来进⾏对象间调⽤

请添加图片描述


http://www.kler.cn/a/541506.html

相关文章:

  • vcredist_x64.exe 是 Microsoft Visual C++ Redistributable 的 64 位版本
  • 嵌入式linux系统中VIM编辑工具用法与GCC参数详解
  • 2025影视泛目录站群程序设计_源码二次开发新版本无缓存刷新不变实现原理
  • 了解“/linux-5.4.31/drivers/of/device.c”中的of_device_get_match_data()
  • android的DataBinding的使用
  • Chapter2:C#基本数据类型
  • 高级java每日一道面试题-2025年02月01日-框架篇[SpringBoot篇]-Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
  • Scala语言的区块链
  • Log4j定制JSON格式日志输出
  • Scala语言的系统运维
  • docker swarm里搭建Selenium Grid分布式测试集群,测试节点随时在线,无需反复启停,效率增倍
  • 构建Ubuntu unminimized的docker镜像
  • 支付宝安全发全套解决方案
  • spring-ai
  • Java 大视界 -- Java 大数据在智能体育中的应用与赛事分析(80)
  • Android 稳定性优化总结
  • 【LeetCode: 378. 有序矩阵中第 K 小的元素 + 二分】
  • 缓存组件<keep-alive>
  • 关于SpringBoot的理解
  • 无人机常见的定位方式
  • Lisp语言的测试开发
  • 十三. Redis 应用问题和解决方案思想
  • 从零到一:我的元宵灯谜小程序诞生记
  • 从MySQL优化到脑力健康:技术人与效率的双重提升
  • IDEA接入DeepSeek
  • 企业级Mysql实战