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

【Linux】:封装线程

朋友们、伙计们,我们又见面了,本期来给大家带来封装线程相关的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!

C 语 言 专 栏:C语言:从入门到精通

数据结构专栏:数据结构

个  人  主  页 :stackY、

C + + 专 栏   :C++

Linux 专 栏  :Linux

​ 

目录

引言:

1. 基础框架 

1.1 初步Start接口

1.2 修正后的Start接口

2. Join接口

 2.1 初步测试

3. 添加模版

4. 全部代码


引言:

我们想要通过封装原生线程库的方式来实现一个类似于C++11里面的线程库,这里只是为了来更沉入的学习原生线程库,实现一些基础的功能即可;

我们创建一个mian.cc文件用于测试线程逻辑;

Thread.hpp主要用于封装线程;

Makefile主要实现自动化代码构建。

1. 基础框架 

  • 我们想要封装的线程需要有对应的线程id、线程名、该线程是否运行以及线程所要执行的任务;
  • 线程所需要执行的任务我们需要用函数包装器(functional)
  • 我们想要实现的方法有一个让线程启动起来的方法,还需要有一个等待线程的方法;
  • 后面根据需要添加对应的成员和方法。

Thread.hpp:

先将基础框架搭建出来,后面再慢慢补充所需要的接口以及代码。

1.1 初步Start接口

在Start接口就是用来启动线程,那么在接口设计中就需要先创建进程,在对应的线程执行方法中执行我们预先设计好的func;

这里就需要注意一下线程封装时的细节,我们先来看一下创建线程的接口具体传递的参数:

我们设置的线程执行方法函数的参数只有一个参数,但是因为我们自己设置的ThreadRoutine函数是类内函数,那么类内函数会默认自己带一个this指针,所以这于原始函数设计接口不符,所以我们需要将该函数设置为静态成员函数,然后我们将this指针传递给他,然后通过this指针来调用我们预设的func;

1.2 修正后的Start接口

2. Join接口

在实现Join之前我们可以设置一个查看线程是否运行的接口以及获取线程名的接口,方便后面的测试;

在等待线程这里我们直接使用原生线程库的接口:

我们目前不关心等待的结果;

 2.1 初步测试

上面的代码算是一份非常简单的线程封装代码,那么接下来我们使用main.cc来使用一下我们封装的线程库,因为我们将线程对象化了,所以我们就可以用容器来保存我们的线程,这其实就是一种“先描述,再组织”的过程。

#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>

#include "Thread.hpp"
// 设置线程名
std::string GetThreadName()
{
    static int num = 1;
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "Thread-%d", num++);
    return buffer;
}

void Print()
{
    while(1)
    {
        std::cout << "hello thread" << std::endl;
        sleep(1);
    }
}

int main()
{
    std::vector<Thread> threads;
    int num = 5;
    // 创建
    for(int i = 0; i< num; i++)
    {
        threads.push_back(Thread(GetThreadName(),Print));
    }
    for (auto &t : threads)
    {
        std::cout << t.ThreadName() << ", is running: " << t.IsRunning() << std::endl;
    }
    // 启动
    for (auto &t : threads)
    {
        t.Start();
    }

    for (auto &t : threads)
    {
        std::cout << t.ThreadName() << ", is running: " << t.IsRunning() << std::endl;
    }
    // Join
    for (auto &t : threads)
    {
        t.Join();
    }
    return 0;
}

3. 添加模版

我们想给我们的线程传递参数,所以我们需要添加模版;

整体代码:

#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>

template <class T>
using func_t = std::function<void(T)>; // 任务

template <class T>
class Thread
{
public:
    Thread(const std::string &threadname, func_t<T> func, T data)
        : _tid(0), _thread_name(threadname), _isrunning(false), _func(func), _data(data)
    {
    }
    // 执行方法
    static void* ThreadRoutine(void *args)
    {
        Thread *ts = static_cast<Thread *>(args);
        ts->_func(ts->_data);
        return nullptr;
    }
    // 启动
    bool Start()
    {
        int n = pthread_create(&_tid, nullptr, ThreadRoutine, this); // 将this指针传递给ThreadRoutine
        if(n == 0)
        {
            _isrunning = true;
            return true;
        }
        else return false;
    }
    // 等待
    bool Join()
    {
        if (!_isrunning)
            return false;
        int n = pthread_join(_tid, nullptr);
        if (n == 0)
        {
            return true;
        }
        return false;
    }
    bool IsRunning()
    {
        return _isrunning;
    }
    std::string ThreadName()
    {
        return _thread_name;
    }
    ~Thread() {}

private:
    pthread_t _tid;           // 线程id
    std::string _thread_name; // 线程名
    bool _isrunning;          // 线程是否运行
    func_t<T> _func;             // 线程所执行任务
    T _data;                   // 传递数据类型
};

4. 全部代码

Makefile

thread:main.cc
	g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
	rm -f thread

main.cc

#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>

#include "Thread.hpp"
// 设置线程名
std::string GetThreadName()
{
    static int num = 1;
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "Thread-%d", num++);
    return buffer;
}

void Print(int num)
{
    while(num--)
    {
        std::cout << "hello thread num :" << num << std::endl;
        sleep(1);
    }
}

int main()
{
    Thread<int> t(GetThreadName(), Print, 5);
    t.Start();
    t.Join();

    // std::vector<Thread> threads;
    // int num = 5;
    // // 创建
    // for(int i = 0; i< num; i++)
    // {
    //     threads.push_back(Thread(GetThreadName(),Print));
    // }
    // for (auto &t : threads)
    // {
    //     std::cout << t.ThreadName() << ", is running: " << t.IsRunning() << std::endl;
    // }
    // // 启动
    // for (auto &t : threads)
    // {
    //     t.Start();
    // }

    // for (auto &t : threads)
    // {
    //     std::cout << t.ThreadName() << ", is running: " << t.IsRunning() << std::endl;
    // }
    // // Join
    // for (auto &t : threads)
    // {
    //     t.Join();
    // }
    // Thread ts(Printf, GetThreadName());
    // std::cout << "is thread running? " << ts.IsRunning() << std::endl;
    // ts.Start();
    // std::cout << "is thread running? " << ts.IsRunning() << std::endl;
    // ts.Join();
    return 0;
}

Thread.hpp

#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>

template <class T>
using func_t = std::function<void(T)>; // 任务

template <class T>
class Thread
{
public:
    Thread(const std::string &threadname, func_t<T> func, T data)
        : _tid(0), _thread_name(threadname), _isrunning(false), _func(func), _data(data)
    {
    }
    // 执行方法
    static void* ThreadRoutine(void *args)
    {
        Thread *ts = static_cast<Thread *>(args);
        ts->_func(ts->_data);
        return nullptr;
    }
    // 启动
    bool Start()
    {
        int n = pthread_create(&_tid, nullptr, ThreadRoutine, this); // 将this指针传递给ThreadRoutine
        if(n == 0)
        {
            _isrunning = true;
            return true;
        }
        else return false;
    }
    // 等待
    bool Join()
    {
        if (!_isrunning)
            return false;
        int n = pthread_join(_tid, nullptr);
        if (n == 0)
        {
            return true;
        }
        return false;
    }
    bool IsRunning()
    {
        return _isrunning;
    }
    std::string ThreadName()
    {
        return _thread_name;
    }
    ~Thread() {}

private:
    pthread_t _tid;           // 线程id
    std::string _thread_name; // 线程名
    bool _isrunning;          // 线程是否运行
    func_t<T> _func;             // 线程所执行任务
    T _data;                   // 传递数据类型
};

相关文章:

  • AutoGen多角色、多用户、多智能体对话系统
  • Qt 数据库操作(Sqlite)
  • 搭建大数据技能竞赛比赛环境容器docker模块A-容器绑定物理网卡
  • Axios简单说明,快速上手
  • 电器维修系统小程序+论文源码调试讲解
  • 为什么 HTTP GET 方法不使用请求体?
  • 前端项目使用多个echarts版本的实践方案
  • ESP-IDF ubuntu版本 V5.2
  • C语言操作MySQL从入门到精通
  • 计算机数据结构-第一章
  • 美畅物联丨WebRTC 技术详解:构建实时通信的数字桥梁
  • springcloud gateway搭建及动态获取nacos注册的服务信息信息
  • C++程序设计语言笔记——抽象机制:运算符重载
  • 14、JavaEE核心技术 - JavaBeans
  • C++设计模式-原型模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析
  • C# NX二次开发:模型导入和向量及点位的使用
  • 连锁企业管理系统 解决了哪些问题
  • ##Hive安装-初始化元数据报错 *** schemaTool failed ***
  • IXTUR气控永磁铁:以高精度气控和稳定磁场,为机器人应用提供稳定抓取力
  • C++复试笔记(二)
  • 创新创业50人论坛开幕在即,双创青年为何选择来上海筑梦?
  • 建筑瞭望|融入自然的新泳池,治愈了中央公园的历史旧伤
  • 李云泽:再批复600亿元,进一步扩大保险资金长期投资试点范围
  • 重温经典|中国首部剪纸动画片《猪八戒吃瓜》创作始末
  • 山东滕州车祸致6人遇难,肇事司机已被刑事拘留
  • 以色列计划“占领加沙”,特朗普下周中东行结束之际将是“机会窗口”