欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

C++11線程池及其三種優(yōu)化-創(chuàng)新互聯(lián)

文章目錄
    • 1. C++11 簡單線程池
    • 2. 優(yōu)化1 - 支持任意類型任務(wù)
    • 3. 優(yōu)化2 - 支持可變參數(shù)
    • 4. 優(yōu)化3 - 通過future獲取任務(wù)函數(shù)的返回值
    • 5. 總結(jié)

?在看這篇文章之前,請(qǐng)先確保大致了解過線程池的基本實(shí)現(xiàn)及其原理。如果不太了解,可以先去閱讀一下這篇文章: pthread線程池的實(shí)現(xiàn)

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)密山免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。1. C++11 簡單線程池

?下面的線程池是基于C++11的線程池。編寫的思路跟前文的pthread實(shí)現(xiàn)的線程池基本一致。

#include#include#include#include#include#include#include   

templateclass ThreadPool
{public:
	ThreadPool(size_t thread_nums = std::thread::hardware_concurrency())
		:_thread_nums(thread_nums)
		, _stop(false)
	{for (size_t i = 0; i< _thread_nums; ++i)
		{	_vt.emplace_back(std::thread(&ThreadPool::LoopWork, this));//將this指針也傳過去
		}
	}

	//禁用拷貝構(gòu)造和operator=  
	ThreadPool(const ThreadPool &) = delete;
	ThreadPool& operator=(const ThreadPool &) = delete;

private:
	//線程的執(zhí)行函數(shù)  
	void LoopWork()
	{std::unique_lockul(_mtx);
		for (;;)
		{	while (_taskQueue.empty() && !_stop)
			{		_isEmpty.wait(ul);
			}

			//線程從wait中出來有2種情況: 1.有任務(wù)了 2.線程池stop為true
			if (_taskQueue.empty()) {		ul.unlock();	//退出前要先解鎖
				break;
			}
			else {		T* task = std::move(_taskQueue.front());
				_taskQueue.pop();
				ul.unlock();
				(*task)();	//任務(wù)類需要重載operator()()
				ul.lock();
			}
		}
	}

public:
	void PushTask(T& task)
	{//通過{}控制lock_guard的作用域和生命周期
		{	std::lock_guardlg(_mtx);
			_taskQueue.push(&task); //任務(wù)隊(duì)列是臨界資源(其他地方會(huì)修改)  
		}
		_isEmpty.notify_one(); //條件變量的通知并不會(huì)因?yàn)槎嗑€程而影響結(jié)果(因此可以不加鎖)
	}


	~ThreadPool()
	{_stop = true;
		_isEmpty.notify_all();
		for (size_t i = 0; i< _thread_nums; ++i)
		{	if (_vt[i].joinable()) {		_vt[i].join();
			}
		}
	}

private:
	size_t _thread_nums;
	std::vector_vt;
	std::queue_taskQueue;
	std::mutex _mtx;
	std::condition_variable _isEmpty;
	std::atomic_stop;
};

struct Task {Task(int x, int y)
		:_x(x),
		 _y(y)
	{}

	void operator()() {std::cout<< _x<< " + "<< _y<< " = "<< _x + _y<< std::endl;
	}

	int _x;
	int _y;
};

int main()
{std::shared_ptr>tp(new ThreadPool());
	Task t(1, 2);
	tp->PushTask(t);
}

輸出結(jié)果:

1 + 2 = 3

?

?

2. 優(yōu)化1 - 支持任意類型任務(wù)

?在前文的pthread線程池以及根據(jù)pthread改寫的C++11線程池都是基于模板實(shí)現(xiàn)的。因?yàn)榫€程池需要能夠接收不同類型的任務(wù)。但是將整個(gè)ThreadPool類設(shè)為模板其實(shí)不是最優(yōu)解,因?yàn)楫?dāng)ThreadPool需要處理其它類型的任務(wù)時(shí),還需要再實(shí)例化出一個(gè)新的ThreadPool類。它并沒有實(shí)現(xiàn)一個(gè)線程池實(shí)例接收多種類型任務(wù)的功能。它實(shí)現(xiàn)的是多個(gè)線程池實(shí)例接收多種類型任務(wù),每個(gè)線程池本質(zhì)是只處理一種任務(wù)。

?為了解決上述問題,我們不應(yīng)該將整個(gè)ThreadPool都設(shè)為模板類,我們的思路是讓任務(wù)隊(duì)列能夠存放不同類型的任務(wù)。這里使用到了C++11中的function包裝器,讓任務(wù)隊(duì)列里存放function類型的任務(wù)。而在PushTask()方法里,我們需要讓該函數(shù)能夠接收任意類型的任務(wù),因此需要單獨(dú)將PushTask()方法設(shè)為模板函數(shù)。

?

#include#include#include#include#include#include#include   

class ThreadPool
{public:
	ThreadPool(size_t thread_nums = std::thread::hardware_concurrency())
		:_thread_nums(thread_nums)
		, _stop(false)
	{for (size_t i = 0; i< _thread_nums; ++i)
		{	_vt.emplace_back(std::thread(&ThreadPool::LoopWork, this));//將this指針也傳過去
		}
	}

	//禁用拷貝構(gòu)造和operator=  
	ThreadPool(const ThreadPool &) = delete;
	ThreadPool& operator=(const ThreadPool &) = delete;

private:
	//線程的執(zhí)行函數(shù)  
	void LoopWork()
	{std::unique_lockul(_mtx);
		for (;;)
		{	while (_taskQueue.empty() && !_stop)
			{		_isEmpty.wait(ul);
			}

			//線程從wait中出來有2種情況: 1.有任務(wù)了 2.線程池stop為true
			if (_taskQueue.empty()) {		ul.unlock();	//退出前要先解鎖
				break;
			}
			else {		auto task = std::move(_taskQueue.front());
				_taskQueue.pop();
				ul.unlock();
				task();
				ul.lock();
			}
		}
	}

public:
	templatevoid PushTask(F&& task)
	{{	std::lock_guardlg(_mtx);
			_taskQueue.push(std::forward(task)); //任務(wù)隊(duì)列是臨界資源(其他地方會(huì)修改)  
		}
		_isEmpty.notify_one(); //條件變量的通知并不會(huì)因?yàn)槎嗑€程而影響結(jié)果(因此可以不加鎖)
	}


	~ThreadPool()
	{_stop = true;
		_isEmpty.notify_all();
		for (size_t i = 0; i< _thread_nums; ++i)
		{	if (_vt[i].joinable()) {		_vt[i].join();
			}
		}
	}

private:
	size_t _thread_nums;
	std::vector_vt;
	std::queue>_taskQueue;//每個(gè)任務(wù)必須保證是: void返回值、無參
	std::mutex _mtx;
	std::condition_variable _isEmpty;
	std::atomic_stop;
};

?

? 優(yōu)化1 - 測試

std::mutex gb_mtx;
void Add(int x, int y)
{std::lock_guardlg(gb_mtx);	//為了保證輸出結(jié)果不會(huì)打印錯(cuò)亂
	std::cout<< x<< " + "<< y<< " = "<< x + y<< std::endl;
}

int main()
{std::shared_ptrtp(new ThreadPool());
	for (int i = 0; i< 10; ++i)
	{auto f = bind(Add, i, i + 1);	//我們需要手動(dòng)綁定一下函數(shù)參數(shù)
		tp->PushTask(f);
	}
	return 0;
}

輸出結(jié)果:

0 + 1 = 1
1 + 2 = 3
2 + 3 = 5
3 + 4 = 7
4 + 5 = 9
5 + 6 = 11
6 + 7 = 13
7 + 8 = 15
8 + 9 = 17
9 + 10 = 19

?

?

3. 優(yōu)化2 - 支持可變參數(shù)

?前一個(gè)版本的線程池是支持任意類型的任務(wù)的,但是我們?cè)谑褂镁€程池的時(shí)候必須要手動(dòng)bind一個(gè)函數(shù)對(duì)象,然后再傳過去(這是因?yàn)槿蝿?wù)隊(duì)列要求任務(wù)必須是void返回值且無參數(shù))。為了優(yōu)化這個(gè)問題,我們可以使用可變參數(shù)模板+bind解決。下面給出PushTask()方法的優(yōu)化:(除了PushTask, 其它地方?jīng)]有任何修改)

templatevoid PushTask(F&& task, Args&&... args)
	{//將可變參數(shù)包裝起來, 包裝后func的類型滿足了"void返回值+無參"
		auto func = std::bind(std::forward(task), std::forward(args)...);
		{	std::lock_guardlg(_mtx);
			_taskQueue.push(std::forward(func)); //傳入我們包裝好的函數(shù)對(duì)象
		}
		_isEmpty.notify_one(); //條件變量的通知并不會(huì)因?yàn)槎嗑€程而影響結(jié)果(因此可以不加鎖)
	}

? 優(yōu)化2 - 測試

std::mutex gb_mtx;
void Add(int x, int y)
{std::lock_guardlg(gb_mtx);	//為了保證輸出結(jié)果不會(huì)打印錯(cuò)亂
	std::cout<< x<< " + "<< y<< " = "<< x + y<< std::endl;
}

int main()
{std::shared_ptrtp(new ThreadPool());
	for (int i = 0; i< 10; ++i)
	{//auto f = bind(Add, i, i + 1);
		//tp->PushTask(f);
		tp->PushTask(Add, i, i + 1);	//我們不需要手動(dòng)綁定了, 直接傳參即可
	}
	return 0;
}

?輸出結(jié)果與測試1的相同。

?

?

4. 優(yōu)化3 - 通過future獲取任務(wù)函數(shù)的返回值

?在優(yōu)化2的基礎(chǔ)上,為了能夠接收任務(wù)函數(shù)的返回值,并且還不能讓線程阻塞。這里需要使用線程異步。我們?cè)?code>PushTask()中需要返回一個(gè)future類型的對(duì)象。下面是對(duì)PushTask()方法的修改。(除了PushTask, 其它地方?jīng)]有任何修改)

注意: 記得包含一下頭文件。

templateauto PushTask(F&& task, Args&&... args) ->std::future{//將可變參數(shù)包裝起來
		auto func = std::bind(std::forward(task), std::forward(args)...);
		auto task_ptr = std::make_shared>(func); //(1)
		std::functionwrapper_func = [task_ptr] {	(*task_ptr)();
		};//(2)

		{	std::lock_guardlg(_mtx);
			_taskQueue.push(wrapper_func); 
		}

		_isEmpty.notify_one(); //條件變量的通知并不會(huì)因?yàn)槎嗑€程而影響結(jié)果(因此可以不加鎖)
		return task_ptr->get_future();//(3)
	}

?在優(yōu)化2的基礎(chǔ)上,我們從(1)開始看。我們使用make_shared構(gòu)造了一個(gè)share_ptr對(duì)象, 方便我們管理。這個(gè)智能指針的類型是package_task。詳細(xì)介紹看這里: C++11 線程異步。這個(gè)package_task中包裝的函數(shù)對(duì)象的類型為decltype(task(args...))()。這個(gè)類型的含義為: 該函數(shù)對(duì)象的返回值的類型為task(args...),函數(shù)參數(shù)為空。

?(2)是對(duì)智能指針再次進(jìn)行了一層封裝,目的為了能夠?qū)⑵渥鳛閰?shù)傳給任務(wù)隊(duì)列。實(shí)際上這里可以省略不寫的,然后更改_taskQueue.push(wrapper_func);

_taskQueue.push([task_ptr]{(*task_ptr)();
	});

?(3)返回智能指針管理的package_task的future對(duì)象。

?

? 優(yōu)化3 - 測試

int Add(int x, int y)
{return x + y;
}

int main()
{std::shared_ptrtp(new ThreadPool());
	std::vector>res;	//future保存的就是函數(shù)的返回值
	for (int i = 0; i< 10; ++i)
	{res.push_back(tp->PushTask(Add, i, i + 1));
	}

	for (auto& e : res)
	{std::cout<< e.get()<< std::endl;
	}
	return 0;
}

輸出結(jié)果:

1
3
5
7
9
11
13
15
17
19

?

?

5. 總結(jié)

?我們實(shí)現(xiàn)的pthread的線程池是基于模板的,因此當(dāng)有不同類型的任務(wù)想要添加到線程池處理時(shí),我們就必須額外創(chuàng)建一個(gè)對(duì)應(yīng)類型的線程池對(duì)象,這個(gè)過程往往不是我們想看到的。為了解決這種問題,我們給出了三種遞進(jìn)式優(yōu)化方案,每種都是基于前面一種的基礎(chǔ)上作的進(jìn)一步優(yōu)化。

?優(yōu)化1: 支持任意類型的任務(wù)函數(shù)。它的本質(zhì)是讓任務(wù)隊(duì)列能夠接收任意類型的任務(wù)函數(shù),我們這里使用了function作為任務(wù)隊(duì)列的類型,也就是說我們?cè)?code>PushTask()時(shí)需要事前包裝好任務(wù)函數(shù),保證其類型為void()。(返回值為void, 參數(shù)為空)

?優(yōu)化2: 支持可變參數(shù)。這是通過可變參數(shù)模板+bind實(shí)現(xiàn)的。我們?cè)试S使用者直接傳任務(wù)函數(shù)以及它的任意個(gè)參數(shù)。我們需要在push任務(wù)前包裝好任務(wù)函數(shù),保證任務(wù)函數(shù)為void()類型。而如何包裝? 這里就需要使用bind進(jìn)行包裝了。
auto func = std::bind(std::forward(task), std::forward(args)...);

?優(yōu)化3: 通過future獲取任務(wù)函數(shù)的返回值。這是通過線程異步實(shí)現(xiàn)的。獲取子線程執(zhí)行完畢的函數(shù)的返回值的方法就是使用異步。因此我們將func任務(wù)函數(shù) 包裝到了package_task任務(wù)包當(dāng)中,package_task中保存了future對(duì)象。這里我們使用了智能指針去管理package_task。由于我們最終的目的是需要將一個(gè)類型為void()的任務(wù)添加到任務(wù)隊(duì)列。因此這里我們使用了lambda表達(dá)式對(duì)智能指針再次進(jìn)行了一層封裝,里面包裝了智能指針去調(diào)用任務(wù)函數(shù)的過程。lambada表達(dá)式的類型就是void(),因此我們可以將其添加到任務(wù)隊(duì)列當(dāng)中。后續(xù)取出任務(wù)后,直接像調(diào)用函數(shù)一樣執(zhí)行任務(wù)即可。(因?yàn)槿蝿?wù)隊(duì)列當(dāng)中存的都是一個(gè)個(gè)的function函數(shù)對(duì)象, 執(zhí)行函數(shù)對(duì)象的方法就是使用operator())

雜談:

?個(gè)人覺得能夠掌握前兩種優(yōu)化就夠了。第三種相對(duì)比較難懂一些,并且沒有太大的必要。我們之所以會(huì)實(shí)現(xiàn)第三種是因?yàn)橄胍@取任務(wù)函數(shù)的返回值! 因?yàn)槲覀冊(cè)?code>優(yōu)化2的狀態(tài)下也能夠獲取到任務(wù)的返回值。我們可以傳入一個(gè)輸出型參數(shù)即可。示例如下:

void Add(int x, int y, int& res)
{res = x + y;
}

int main()
{std::shared_ptr>tp(new ThreadPool());
	int res;
	tp->PushTask(Add, 1, 2, std::ref(res));	//注意, 這里必須要使用``ref()``引用傳參!!!
	std::cout<< res<< std::endl;
	return 0;
}

輸出結(jié)果: 3

?

注: 還有很多人會(huì)將taskQueue任務(wù)隊(duì)列封裝成一個(gè)類*(SafeQueue)*,然后封裝任務(wù)隊(duì)列的各種接口,將各種加鎖、解鎖操作都封裝到了該類里面。外界在使用該類時(shí),不需要再額外考慮鎖的問題了。

?

參考:

Github: mtrebi/thread-pool: Thread pool implementation using c++11 threads

https://zhuanlan.zhihu.com/p/367309864

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

文章標(biāo)題:C++11線程池及其三種優(yōu)化-創(chuàng)新互聯(lián)
網(wǎng)站鏈接:http://aaarwkj.com/article22/dihijc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、云服務(wù)器、動(dòng)態(tài)網(wǎng)站營銷型網(wǎng)站建設(shè)外貿(mào)建站、手機(jī)網(wǎng)站建設(shè)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
久久熟妇少妇亚洲精品| 日本最新一区二区三区视频| 亚洲天堂毛片在线观看| 成人短篇在线视频夫妻刺激自拍| 日本a亚洲中文字幕永远| 国产黄色看三级91大片| 国产精品一区二区三区 在线| 香蕉视频欧美久久精品| 国产一区二区三区日本精品| 日本电影在线看一区二区| av天堂男人站在线观看| 日本午夜福利久久久| 欧美中文日韩国产字幕| 一区二区三区免费在线观看视频| 激情小说婷婷亚洲综合| 国产成人一区二区二区三区 | 哪里可以看日韩免费毛片| 在线观看中文字幕一区| 91九色在线免费观看| 色日韩在线观看视频| 尤物视频在线观看一下| 中文字幕乱码亚洲中文在线| 美女丝袜诱惑国产91| 亚洲激情在线观看一区| 亚洲三级av在线播放| 亚洲欧美成人自偷自拍一区| 精品国产一区二区三区不卡| 欧美日韩亚洲精品三级 | 国产麻豆剧传媒精品av| 亚洲熟妇中文字幕五十中出| 在线观看亚洲毛片网站| 日韩精品二区在线观看| 亚洲黄色成人在线观看| 日韩黄色成人在线观看| 国产激情在线四五区观看| 密桃精品一区二区三区在线观看| 亚洲成人日韩欧美在线| 久久久久亚洲av成人网人| 视频一区中文字幕在线| 国产精品99久久久久久人| 欧美在线免费黄片视频|