【线程概念与控制】:线程封装

thread.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <functional>
#include <pthread.h>

namespace ThreadModule
{
    static uint32_t number = 1; // 第几个创建的线程

    using func_t = std::function<void()>; // 包装器

    class Thread
    {
    private:
        void EnableDetach()
        {
            _isDetach = true;
        }
        void EnableRunning()
        {
            _isRunning = true;
        }
        // void* Routine(Thread* this,void* args)
        //  静态成员函数,参数不带this指针
        static void *Routine(void *args)
        {
            //std::cout << "Routine" << std::endl;
            Thread *self = static_cast<Thread *>(args);
            self->_isRunning = true;
            // 如果设置为分离,调用pthread_datach结束后自动回收线程
            if (self->_isDetach)
                self->Detach();

            // 设置线程名
            pthread_setname_np(self->_tid, self->_name.c_str());
            // 回调函数,执行线程任务
            self->_func();

            return nullptr;
        }

    public:
        Thread(func_t func)
            : _tid(pthread_self()),
              _isDetach(false),
              _isRunning(false),
              _res(nullptr),
              _func(func)
        {
            _name = "thread-" + std::to_string(number++);
        }
        // 开始线程
        bool Start()
        {
            if (_isRunning) // 二次运行
                return false;

            int n = pthread_create(&_tid, NULL, Routine, this);
            if (n == 0)
            {
                std::cout << "线程创建成功..." << std::endl;
                return true;
            }
            else
            {
                std::cerr << "线程创建失败..." << strerror(n) << std::endl;
                return false;
            }

            EnableRunning();
        }
        // 分离线程,使用 pthread_datach,线程结束后自动回收
        void Detach()
        {
            if (_isDetach)
                return;

            // 分离、更新状态
            if (_isRunning)
                pthread_detach(_tid);
            EnableDetach();
        }
        // 停止线程
        bool Stop()
        {
            if (_isRunning)
            {
                // 取消一个正在执行的线程
                int n = pthread_cancel(_tid);
                if (n == 0)
                {
                    std::cout << _name << ",stop success!" << std::endl;
                    return true;
                }
                else
                {
                    std::cerr << "线程取消失败:" << strerror(n) << std::endl;
                    return false;
                }
            }
            return false;
        }
        // 收回线程
        void Join()
        {
            // 已经分离的线程不能手动回收
            if (_isDetach)
            {
                std::cout << "线程已经是分离的的了,不能再join" << std::endl;
                return;
            }

            int n = pthread_join(_tid, &_res);
            if (n == 0)
            {
                std::cout << "join success..." << std::endl;
            }
            else
            {
                std::cerr << "join error..." << strerror(n) << std::endl;
            }
        }
        ~Thread()
        {
        }

    private:
        pthread_t _tid;
        std::string _name;

        bool _isDetach;  // 线程是否分离
        bool _isRunning; // 线程是否运行

        void *_res;   // pthread_join(&tid,res); res是输出型参数,保存线程的退出返回值
        func_t _func; // 回调函数
    };
}

成员变量:

  • 线程 id
  • 自定义线程名
  • 是否分离标志位
  • 是否运行标志位
  • 输出形参数res,pthread_join(&tid,res),线程的退出状 态
  • 线程调用函数
  • Start 函数:如果还未运行,调用 pthread_create 设置线程的调用函数,并传入 this 指针。
  • Routine 函数:线程的调用函数,必须是静态成员函数(static),因为 C++普通的成员函数第一个参数是一个隐式的 this 指针。static函数不带。Routine函数最后会回调 func 函数,即线程会调用func 函数
  • Detach 函数:调用 pthread_detach 函数,线程结束后自动回收。
  • Join 函数:调用 pthread_join 函数,手动回收线程。
  • Stop 函数:调用pthread_cancel 函数,取消一个正在执行的线程。

Main.cc

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include <vector>
#include "Thread.hpp"

using namespace ThreadModule;

void func()
{
    while (true)
    {
        // 获取线程名
        char name[1024];
        pthread_getname_np(pthread_self(), name, sizeof(name));
        std::cout << "我是一个新线程:" << name << std::endl;
        sleep(1);
    }
}

int main()
{
    // 创建10个子进程,使用vector存储
    std::vector<Thread> td;
    for (int i = 0; i < 10; i++)
    {
        //td.emplace_back(Thread(func()));// func()是函数调用,不是传参
        //td.emplace_back(Thread(func));// 显示插入
        //td.emplace_back(func);// 隐式转换

        // Lambada表达式
        // Lambda表达式
        //     ↓ (隐式转换)
        // std::function<void()> (即 func_t)
        //     ↓ (匹配Thread构造函数)
        // Thread(func_t func)
        //     ↓ (emplace_back在vector内部构造)
        // Thread对象
        td.emplace_back([]()
                        {
            while(true)
            {
                // 获取线程名
                char name[1024];
                pthread_getname_np(pthread_self(),name,sizeof(name));
                std::cout<<"我是一个新线程:"<<name<<std::endl;
                sleep(1);
            } });
    }

    // 开始+回收线程
    for (auto &thread : td)
    {
        // Start负责创建线程,设置调用函数,调用Rouine,Rouine内部回调func
        thread.Start();
    }
    for (auto &thread : td)
    {
        thread.Join();
    }

    return 0;
}

使用 vector 管理线程。

插入线程的流程是:

  • 使用 emplace_back 向 vector 中插入元素,我们这边插入的是 Lambda 表达式,即插入一个 void() 函数。
  • Lambda 表达式隐式转换->std::function<void()> (即 func_t),func_t 类型与 Thread 的构造函数匹配,于是就创建了一个 Thread 对象。

插入 Thread 对象时,不能这样插入:td.emplace_back(Thread(func())); 因为func()是函数调用,不是传参。可以 td.emplace_back(Thread(func)); 显示传参,也可以 td.emplace_back(func); 走隐式类型转换。

相关推荐
学习,学习,在学习1 小时前
Qt工控仪器程序框架设计详解(工控多仪器控制版本)
开发语言·c++·qt
kyle~1 小时前
工程数学---点云配准卡布施(Kabsch)算法(求解最优旋转矩阵)
线性代数·算法·矩阵
张二娃同学1 小时前
03_变量常量与输入输出_printf与scanf详解
算法
信竞星球_少儿编程题库2 小时前
2026年全国信息素养大赛算法应用主题赛 丝路新城 C++ 模拟卷(三)
开发语言·c++
Zhang~Ling2 小时前
深入解析C++list:从0到1实现一个完整的链表类
c++·链表·list
江南十四行2 小时前
并发编程(一)
java·jvm·算法
2301_783848652 小时前
mysql数据库迁移到云平台流程_使用数据传输服务DTS工具
jvm·数据库·python
Dicky-_-zhang2 小时前
自动化运维实战:监控告警与自动化运维的完整方案
java·jvm
z200509302 小时前
今日算法(依旧二叉树)
算法·leetcode·职场和发展