【Linux】:封装线程

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

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

数据结构专栏:数据结构

个 人 主 页 :stackY、

C + + 专 栏 :C++

Linux 专 栏 :Linux

目录

引言:

[1. 基础框架](#1. 基础框架)

[1.1 初步Start接口](#1.1 初步Start接口)

[1.2 修正后的Start接口](#1.2 修正后的Start接口)

[2. Join接口](#2. Join接口)

[2.1 初步测试](#2.1 初步测试)

[3. 添加模版](#3. 添加模版)

[4. 全部代码](#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来使用一下我们封装的线程库,因为我们将线程对象化了,所以我们就可以用容器来保存我们的线程,这其实就是一种"先描述,再组织"的过程。

cpp 复制代码
#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. 添加模版

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

整体代码:

cpp 复制代码
#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

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

main.cc

cpp 复制代码
#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

cpp 复制代码
#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;                   // 传递数据类型
};
相关推荐
郑州吴彦祖7722 天前
《深入解析Java synchronized死锁:从可重入锁到哲学家就餐问题》
java·线程·synchronized
charlie1145141918 天前
从0开始的操作系统手搓教程21:进程子系统的一个核心功能——简单的进程切换
汇编·学习·操作系统·线程·进程·手搓教程
magic 24515 天前
深入理解Java多线程编程:从基础到高级应用
java·开发语言·线程
SuperHeroWu721 天前
【HarmonyOS Next】鸿蒙应用进程和线程详解
华为·线程·进程·harmonyos·鸿蒙
小沈同学呀22 天前
SpringBoot中使用 ThreadLocal 进行多线程上下文管理及其注意事项
java·spring boot·后端·线程·thread·threadlocal
清水加冰1 个月前
【Linux线程】线程控制
linux·c++·线程
韩曙亮1 个月前
【系统架构设计师】操作系统 - 进程管理 ① ( 进程概念 | 进程组成 | 进程 与 程序 | 进程 与 线程 | 线程 可共享的资源 - ☆考点 )
操作系统·线程·进程·软考·进程管理·程序·系统架构设计师
zwhSunday1 个月前
线程概念、操作
linux·线程
无双@2 个月前
简单封装线程库 + 理解LWP和TID
linux·c++·操作系统·线程·进程·大作业