欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于C++17實現(xiàn)的手寫線程池

 更新時間:2024年08月21日 09:32:33   作者:吃我一個平底鍋  
本文主要介紹了基于C++17實現(xiàn)的手寫線程池,自己實現(xiàn)了Any類,Semaphore類以及Result類的開發(fā),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

接著上文,我們使用了基于C++11實現(xiàn)的手寫線程池,自己實現(xiàn)了Any類,Semaphore類以及Result類的開發(fā),其中很多細(xì)節(jié)是值得學(xué)習(xí)的,隨著不斷更新,在C++17中提供future類,使得代碼更加輕量化。接下來我們來看一下源碼剖析:

threadpool.h

在最終版,除去 submitTask 以及 threadFunc 其余部分和基于C++11是一樣的,這里不自定義Any類,Semaphore類以及Result類,使用C++17中提供的future類,并且支持用戶輸入任意類型,任意參數(shù)數(shù)量的任務(wù).
首先,定義了一個Task任務(wù),不確定函數(shù)返回值類型

using Task = std::function<void()>;

submitTask

template<typename Func,typename... Args> //右值引用,引用折疊,可變參

auto submitTask(Func&& func, Args&&... args) -> std::future<decltype(func(args...))>
{
	//打包任務(wù) 放入任務(wù)隊列里面
	using RType = decltype(func(args...));  //返回值類型
	auto task = std::make_shared<std::packaged_task<RType()>>(
		std::bind(std::forward<Func>(func), std::forward<Args>(args)...)); //forward保持左值或者右值特性
	std::future<RType> result = task->get_future(); //把參數(shù)全部綁定到函數(shù)上


	//獲取鎖
	std::unique_lock<std::mutex> lock(taskQueMtx_);


	if (!notFull_.wait_for(lock, std::chrono::seconds(1),
		[&]()->bool {return taskQue_.size() < (size_t)taskQueMaxThresHold_; }))
	{

		std::cerr << "task queue is full,submit task fail." << std::endl;
		auto task = std::make_shared<std::packaged_task<RType()>>(
			[]()->RType { return RType(); }); 
		(*task)(); 
		return task->get_future();;
	}

	taskQue_.emplace([task]() {
		(*task)(); }); 
		
	taskSize_++;


	notEmpty_.notify_all();


	if (poolMode_ == PoolMode::MODE_CACHED
		&& taskSize_ > idleThreadSize_
		&& curThreadSize_ < threadSizeThresHold_)
	{

		std::cout << ">>> create new thread" << std::endl;

		//創(chuàng)建thread線程對象
		auto ptr = std::make_unique<Thread>(std::bind(&ThreadPool::threadFunc, this, std::placeholders::_1));
		//threads_.emplace_back(std::move(ptr)); //資源轉(zhuǎn)移
		int threadId = ptr->getId();
		threads_.emplace(threadId, std::move(ptr));
		threads_[threadId]->start(); //啟動線程

		//修改線程個數(shù)相關(guān)的變量
		curThreadSize_++;
		idleThreadSize_++;
	}

	//返回任務(wù)的Result對象
	return result;


}
  • 為了讓submitTask可以接收任意任務(wù)函數(shù)和任意數(shù)量的參數(shù),我們使用可變參模板編程template<typename Func,typename... Args>;
  • submitTask返回的類型是由decltype推導(dǎo)出來的,func(args…) 參數(shù)傳入函數(shù),通過decltype可以推導(dǎo)出來類型,但是不會計算表達(dá)式;
  • 打包任務(wù) 放入任務(wù)隊列里面,使用 decltype(func(args…)); 來確定返回值類型RType;
  • 確定task,把參數(shù)全部綁定到函數(shù)上
  • 把參數(shù)全部綁定到函數(shù)上;
  • 通過future類的get_future(); 獲取返回值

接下來就執(zhí)行任務(wù),由于using Task = std::function<void()>;任務(wù)隊列的任務(wù)沒有返回值,但是上面的task有返回值,所以使用中間層匿名函數(shù)對象,當(dāng)調(diào)用匿名函數(shù)時,實際上就是調(diào)用(*task)();,task解引用以后就是packaged_task,然后()執(zhí)行了task任務(wù),在線程函數(shù)中,執(zhí)行task()相當(dāng)于就執(zhí)行了packaged_task對象。

啟動線程,執(zhí)行線程函數(shù)

void threadFunc(int threadid)
{
	auto lastTime = std::chrono::high_resolution_clock().now();
	for (;;)
	{
		Task task;
		{
			//獲取鎖
			std::unique_lock<std::mutex> lock(taskQueMtx_);
			std::cout << "tid:" << std::this_thread::get_id()<< "嘗試獲取任務(wù)..." << std::endl;

			while (taskQue_.size() == 0)
			{

				if (!isPoolRuning_)
				{
					threads_.erase(threadid);
					std::cout << "threadid:" << std::this_thread::get_id()
						<< "exit!" << std::endl;

					exitCond_.notify_all();
					return;
				}

				if (poolMode_ == PoolMode::MODE_CACHED)
				{	//超時返回std::cv_status::timeout
					if (std::cv_status::timeout ==
						notEmpty_.wait_for(lock, std::chrono::seconds(1)))
					{
						auto now = std::chrono::high_resolution_clock().now();
						auto dur = std::chrono::duration_cast<std::chrono::seconds>(now - lastTime);
						if (dur.count() >= THREAD_MAX_IDLE_TIME&& curThreadSize_ > initThreadSize_)
						{
							threads_.erase(threadid);
							curThreadSize_--;
							idleThreadSize_--;

							std::cout << "threadid:" << std::this_thread::get_id()<< "exit!" << std::endl;
							return;
						}
					}
				}
				else
				{
					//等待notEmpty_條件
					notEmpty_.wait(lock);
				}
			}

			idleThreadSize_--;

			std::cout << "tid:" << std::this_thread::get_id()
				<< "獲取任務(wù)成功..." << std::endl;

			//從任務(wù)隊列中取一個任務(wù)出來
			task = taskQue_.front();
			taskQue_.pop();
			taskSize_--;

			//若依然有剩余任務(wù),繼續(xù)通知其他線程執(zhí)行任務(wù)
			if (taskQue_.size() > 0)
			{
				notEmpty_.notify_all();
			}
			notFull_.notify_all();
		}

		if (task != nullptr)
		{
			task(); //執(zhí)行std::function<void()>;
		}
		idleThreadSize_++;

		auto lastTime = std::chrono::high_resolution_clock().now();
	}
}

除去執(zhí)行任務(wù)的地方改變了,其余沒變;

這里取出task,然后task(); 相當(dāng)于執(zhí)行了(*task)();也就是執(zhí)行了packaged_task對象。

測試文件

#include <iostream>
#include <functional>
#include <thread>
#include <future>
#include <chrono>

#include "threadpool.h"

using namespace std;


int sum1(int a, int b)
{
	std::this_thread::sleep_for(std::chrono::seconds(5));
	return a + b;
}

int sum2(int a, int b,int c)
{
	std::this_thread::sleep_for(std::chrono::seconds(5));
	return a + b + c;
}

int main()
{
	ThreadPool pool;

	//pool.setMode(PoolMode::MODE_CACHED);

	pool.start(2);

	future<int> res1 = pool.submitTask(sum1, 1, 2);
	future<int> res2 = pool.submitTask(sum2, 1, 2,3);
	future<int> res3 = pool.submitTask([](int d, int e)->int {
		int sum = 0;
		for (int i = d; i < e; i++)
			sum += i;
		return sum;
		},1, 100);

	future<int> res4 = pool.submitTask([](int d, int e)->int {
		int sum = 0;
		for (int i = d; i < e; i++)
			sum += i;
		return sum;
		}, 1, 100);

	future<int> res5 = pool.submitTask([](int d, int e)->int {
		int sum = 0;
		for (int i = d; i < e; i++)
			sum += i;
		return sum;
		}, 1, 100);

	cout << res1.get() << endl;
	cout << res2.get() << endl;
	cout << res3.get() << endl;
	cout << res4.get() << endl;
	cout << res5.get() << endl;
}

ThreadPool定義對象,開啟線程,2個線程

這里可以提交任意類型的,任意參數(shù)個數(shù)的任務(wù)以及匿名函數(shù);

在這里插入圖片描述

pool.setMode(PoolMode::MODE_CACHED); 下:

在這里插入圖片描述

好了~ 基于C++17實現(xiàn)的線程池就剖析結(jié)束了,實際上使用了future類以及packaged_task(function函數(shù)對象),方便了我們項目的實現(xiàn),更多相關(guān)C++17 手寫線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++中Boost的智能指針scoped_ptr

    C++中Boost的智能指針scoped_ptr

    這篇文章介紹了C++中Boost的智能指針scoped_ptr,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • QT5實現(xiàn)TTS文本語音朗讀功能

    QT5實現(xiàn)TTS文本語音朗讀功能

    TTS?語音朗讀?是開發(fā)中常用的功能,Qt已經(jīng)給封裝完成,我們只需要調(diào)用即可,本文就為大家介紹了QT5如何調(diào)用實現(xiàn)文本朗讀功能的,需要的可以參考一下
    2023-05-05
  • 詳細(xì)了解C語言二叉樹的建立與遍歷

    詳細(xì)了解C語言二叉樹的建立與遍歷

    這篇文章主要介紹了C中二叉樹的建立和各種遍歷實例代碼,涉及樹節(jié)點的定義,后序遍歷,層序遍歷,深度優(yōu)先和廣度優(yōu)先等相關(guān)內(nèi)容,具有一定借鑒價值,需要的朋友可以參考下
    2021-07-07
  • Mac OS上搭建Apache+PHP+MySQL開發(fā)環(huán)境的詳細(xì)教程

    Mac OS上搭建Apache+PHP+MySQL開發(fā)環(huán)境的詳細(xì)教程

    這篇文章主要介紹了Mac OS上搭建Apache+PHP+MySQL開發(fā)環(huán)境的詳細(xì)教程,包括常見的PHP連接MySQL失敗問題的解決辦法,需要的朋友可以參考下
    2016-01-01
  • C語言繪制雷達(dá)圖的示例代碼

    C語言繪制雷達(dá)圖的示例代碼

    常用的統(tǒng)計圖有條形圖、柱形圖、折線圖、曲線圖、餅圖、環(huán)形圖、扇形圖,其中還有一種雷達(dá)圖的繪制也較難,本文為大家提供了雷達(dá)圖的繪制方法,需要的可以參考下
    2024-02-02
  • 圖文詳解c/c++中的多級指針與多維數(shù)組

    圖文詳解c/c++中的多級指針與多維數(shù)組

    多維數(shù)組與多級指針是初學(xué)者經(jīng)常感覺迷糊的一個地方。超過二維的數(shù)組和超過二級的指針其實并不多用。但只要掌握一定的方法,理解多級指針和“多維”數(shù)組完全可以像理解一級指針和一維數(shù)組那樣簡單。
    2016-08-08
  • C++中命名空間(namespace)詳解及其作用介紹

    C++中命名空間(namespace)詳解及其作用介紹

    考慮一種情況,當(dāng)我們有兩個同名的人,Zara,在同一個班里。當(dāng)我們需要對它們進(jìn)行區(qū)分我們必須使用一些額外的信息和它們的名字,比如它們生活在不同的區(qū)域或者興趣愛好什么的,在C++程序中也會遇到同樣的情況,所以命名空間就此產(chǎn)生
    2022-08-08
  • 深入解讀C++ 內(nèi)聯(lián)函數(shù)inline|nullptr

    深入解讀C++ 內(nèi)聯(lián)函數(shù)inline|nullptr

    內(nèi)聯(lián)函數(shù):用** inline 修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時C++編譯器會在調(diào)用的地方展開內(nèi)聯(lián)函數(shù)**,這樣調(diào)用內(nèi)聯(lián)函數(shù)就需要創(chuàng)建棧楨,就提高效率了,這篇文章給大家介紹C++ 內(nèi)聯(lián)函數(shù)inline|nullptr的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • C語言if選擇結(jié)構(gòu)語句詳解

    C語言if選擇結(jié)構(gòu)語句詳解

    大家好,本篇文章主要講的是C語言if選擇結(jié)構(gòu)語句詳解,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • C語言詳細(xì)圖解浮點型數(shù)據(jù)的存儲實現(xiàn)

    C語言詳細(xì)圖解浮點型數(shù)據(jù)的存儲實現(xiàn)

    使用編程語言進(jìn)行編程時,需要用到各種變量來存儲各種信息。變量保留的是它所存儲的值的內(nèi)存位置。這意味著,當(dāng)您創(chuàng)建一個變量時,就會在內(nèi)存中保留一些空間。您可能需要存儲各種數(shù)據(jù)類型的信息,操作系統(tǒng)會根據(jù)變量的數(shù)據(jù)類型,來分配內(nèi)存和決定在保留內(nèi)存中存儲什么
    2022-05-05

最新評論