朋友们、伙计们,我们又见面了,本期来给大家带来封装线程相关的知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成!
C 语 言 专 栏:C语言:从入门到精通
数据结构专栏:数据结构
个 人 主 页 :stackY、
C + + 专 栏 :C++
Linux 专 栏 :Linux
目录
引言:
我们想要通过封装原生线程库的方式来实现一个类似于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; // 传递数据类型 };