朋友們、伙計們,我們又見面了,本期來給大家帶來封裝線程相關的知識點,如果看完之后對你有一定的啟發,那么請留下你的三連,祝大家心想事成!
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;}// Joinfor (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指針傳遞給ThreadRoutineif(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; // 線程idstd::string _thread_name; // 線程名bool _isrunning; // 線程是否運行func_t<T> _func; // 線程所執行任務T _data; // 傳遞數據類型 };
4. 全部代碼
Makefile
thread:main.ccg++ -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指針傳遞給ThreadRoutineif(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; // 線程idstd::string _thread_name; // 線程名bool _isrunning; // 線程是否運行func_t<T> _func; // 線程所執行任務T _data; // 傳遞數據類型 };