C++實(shí)現(xiàn)線程池的簡單方法示例
最近自己寫了一個(gè)線程池。
總的來說,線程池就是有一個(gè)任務(wù)隊(duì)列,一個(gè)線程隊(duì)列,線程隊(duì)列不斷地去取任務(wù)隊(duì)列中的任務(wù)來執(zhí)行,當(dāng)任務(wù)隊(duì)列中為空時(shí),線程阻塞等待新的任務(wù)添加過來。
我是用queue來存放任務(wù),vector存放thread*,然后用condition_variable 來設(shè)置線程阻塞和喚醒。
下面直接上代碼吧。
線程池類頭文件Thread_Pool.h
/********************************************
線程池頭文件
Author:十面埋伏但莫慌
Time:2020/05/03
*********************************************/
#pragma once
#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_
#include<thread>
#include<queue>
#include<mutex>
#include<atomic>
#include<vector>
#include<condition_variable>
typedef std::function<void()> Func;//定義線程執(zhí)行函數(shù)類型,方便后面編碼使用。
//任務(wù)類
class Task {
public:
Task() {}
~Task() {}
int push(Func func);//添加任務(wù);
int getTaskNum();//獲得當(dāng)前隊(duì)列中的任務(wù)數(shù);
Func pop();//取出待執(zhí)行的任務(wù);
public:
std::mutex mx;//鎖;
private:
std::queue<Func> tasks;//任務(wù)隊(duì)列
};
//線程池類
class Thread_Pool {
public:
Thread_Pool() :IsStart(false) {}
~Thread_Pool();
int addTasks(Func tasks);//添加任務(wù);
void start();//開啟線程池;
void stop();//關(guān)閉線程池;
void run();//線程工作函數(shù);
int getTaskNum();//獲得當(dāng)前隊(duì)列中的任務(wù)數(shù);
private:
static const int maxThreadNum = 3;//最大線程數(shù)為3;
std::condition_variable cond;//條件量;
std::vector<std::thread*> threads;//線程向量;
std::atomic<bool> IsStart;//原子變量,判斷線程池是否運(yùn)行;
Task tasks;//任務(wù)變量;
};
#endif
然后是線程池類成員函數(shù)定義文件Thread_Pool.cpp
/********************************************
線程池CPP文件
Author:十面埋伏但莫慌
Time:2020/05/03
*********************************************/
#include"Thread_Pool.h"
#include<iostream>
int Task::push(Func func) {
std::unique_lock<std::mutex> lock(mx);
try {
tasks.emplace(func);
}
catch (std::exception e)
{
throw e;
return -1;
}
return 0;
}
int Task::getTaskNum()
{
return tasks.size();
}
Func Task::pop() {
std::unique_lock<std::mutex> lock(mx);
Func temp;
if (tasks.empty())
return temp;
else
{
temp = tasks.front();
tasks.pop();
return temp;
}
}
int Thread_Pool::addTasks(Func func)
{
int ret = tasks.push(func);
cond.notify_one();
return ret;
}
void Thread_Pool::start() {
if (!IsStart) {
IsStart = true;
for (int i = 0; i < maxThreadNum; i++)
{
threads.emplace_back(new std::thread(std::bind(&Thread_Pool::run,this)));
}
}
}
void Thread_Pool::run()
{
while (IsStart)
{
Func f;
if (tasks.getTaskNum() == 0 && IsStart)
{
std::unique_lock<std::mutex> lock(tasks.mx);
cond.wait(lock);
}
if (tasks.getTaskNum() != 0 && IsStart)
{
f = tasks.pop();
if(f)
f();
}
}
}
int Thread_Pool::getTaskNum() {
return tasks.getTaskNum();
}
void Thread_Pool::stop() {
IsStart = false;
cond.notify_all();
for (auto T : threads) {
std::cout << "線程 " << T->get_id() << " 已停止。" << std::endl;
T->join();
if (T != nullptr)
{
delete T;
T = nullptr;
}
}
std::cout << "所有線程已停止。" << std::endl;
}
Thread_Pool::~Thread_Pool() {
if (IsStart)
{
stop();
}
}
最后是測試用的main.cpp
#include<iostream>
#include"Thread_Pool.h"
using namespace std;
void string_out_one() {
cout << "One!" << endl;
}
void string_out_two() {
cout << "Two!" << endl;
}
void string_out_three() {
cout << "Three!" << endl;
}
int main() {
{
Thread_Pool Pool;
try {
Pool.start();
}
catch (std::exception e)
{
throw e;
cout << "線程池創(chuàng)建失敗。" << endl;
}
for (int i = 0; i < 50000 ;)
{
if (Pool.getTaskNum() < 1000) {
Pool.addTasks(string_out_one);
Pool.addTasks(string_out_two);
Pool.addTasks(string_out_three);
std::cout << i++ << std::endl;
}
}
getchar();
}
getchar();
return 0;
}
執(zhí)行的效果如下:

線程喚醒和阻塞的邏輯就是在線程工作函數(shù)run函數(shù)中,判斷隊(duì)列是否為空,若為空則設(shè)置鎖并調(diào)用condition變量的wait函數(shù),釋放這個(gè)線程中的鎖并阻塞線程,等待任務(wù)隊(duì)列中新的任務(wù)添加進(jìn)來后,
condition變量通過notify_one()隨機(jī)喚醒一個(gè)在wait的線程,取出隊(duì)列中的任務(wù)執(zhí)行。
寫這個(gè)線程池的過程中碰到的最主要需要注意的就是鎖的使用,在對(duì)隊(duì)列的寫和釋放時(shí)要注意加鎖,在需要阻塞線程時(shí),要注意通過{}設(shè)置鎖的范圍。
IsStart是原子的,所以在寫這個(gè)變量的時(shí)候沒有另外加鎖。
目前我覺得這個(gè)線程池的缺陷就是可執(zhí)行函數(shù)的類型被寫死了,有嘗試對(duì)Task類使用模板類,但是在Thread_Pool中還是要指明Task模板類的類型參數(shù),要是有大神指點(diǎn)下就好了- -。
就先記錄這么多,感覺這個(gè)線程池的還是有很多可以改進(jìn)的地方的,也歡迎大家指出不足。
到此這篇關(guān)于C++實(shí)現(xiàn)線程池的簡單方法的文章就介紹到這了,更多相關(guān)C++實(shí)現(xiàn)線程池內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 基于C++17實(shí)現(xiàn)的手寫線程池
- 基于C++11實(shí)現(xiàn)手寫線程池的示例代碼
- C++ 學(xué)習(xí)筆記實(shí)戰(zhàn)寫一個(gè)簡單的線程池示例
- C++單例模式實(shí)現(xiàn)線程池的示例代碼
- C++實(shí)現(xiàn)一個(gè)簡單的線程池的示例代碼
- C++線程池實(shí)現(xiàn)代碼
- C/C++ 原生API實(shí)現(xiàn)線程池的方法
- C++11 簡單實(shí)現(xiàn)線程池的方法
- 深入解析C++編程中線程池的使用
- c++實(shí)現(xiàn)簡單的線程池
- c++線程池實(shí)現(xiàn)方法
- C++線程池實(shí)現(xiàn)
相關(guān)文章
win32 api實(shí)現(xiàn)簡單的消息窗口示例
這篇文章主要介紹了使用win32 api實(shí)現(xiàn)簡單的消息窗口示例,需要的朋友可以參考下2014-03-03
C語言創(chuàng)建鏈表錯(cuò)誤之通過指針參數(shù)申請(qǐng)動(dòng)態(tài)內(nèi)存實(shí)例分析
這篇文章主要介紹了C語言創(chuàng)建鏈表錯(cuò)誤之通過指針參數(shù)申請(qǐng)動(dòng)態(tài)內(nèi)存,是鏈表創(chuàng)建過程中非常常見的經(jīng)典錯(cuò)誤。實(shí)例中做了較為詳盡的分析,需要的朋友可以參考下2014-09-09
C語言數(shù)據(jù)結(jié)構(gòu)之堆、堆排序的分析及實(shí)現(xiàn)
堆是一個(gè)近似完全二叉樹的結(jié)構(gòu),并同時(shí)滿足堆積的性質(zhì),下面這篇文章主要給大家介紹了關(guān)于C語言數(shù)據(jù)結(jié)構(gòu)之堆、堆排序的分析及實(shí)現(xiàn)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
C++實(shí)現(xiàn)優(yōu)先隊(duì)列的示例詳解
普通的隊(duì)列是一種先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),元素在隊(duì)列尾追加,而從隊(duì)列頭刪除。在優(yōu)先隊(duì)列中,元素被賦予優(yōu)先級(jí)。本文將用C++實(shí)現(xiàn)優(yōu)先隊(duì)列,需要的可以參考一下2022-06-06

