@TOC


📝線程封裝

🌉 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

Linux模擬線程封裝與智能指針shared_ptr_ios

Linux模擬線程封裝與智能指針shared_ptr_ios_02

🌠線程封裝第二版

🌉 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();
    }

Linux模擬線程封裝與智能指針shared_ptr_#include_03

Linux模擬線程封裝與智能指針shared_ptr_ios_04

🌠單線程創建測試

🌉 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;
}

Linux模擬線程封裝與智能指針shared_ptr_#include_05

Linux模擬線程封裝與智能指針shared_ptr_#include_06

🌠智能指針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來進⾏對象間調⽤