VC實現執行緒池
你也可以把沒有等待操作的工作專案放到執行緒池中,用QueueUserWorkItem函式來完成這個工作,把要執行的工作專案函式通過一個引數傳遞給執行緒池。工作專案被放到執行緒池中後,就不能再取消了。
Timer-queue timers和Registered wait operations也使用執行緒池來實現。他們的回撥函式也放線上程池中。你也可以用BindIOCompletionCallback函式來投遞一個非同步IO操作,在IO完成埠上,回撥函式也是由執行緒池執行緒來執行。
當第一次呼叫QueueUserWorkItem函式或者BindIOCompletionCallback函式的時候,執行緒池被自動建立,或者Timer-queue timers或者Registered wait operations放入回撥函式的時候,執行緒池也可以被建立。執行緒池可以建立的執行緒數量不限,僅受限於可用的記憶體,每一個執行緒使用預設的初始堆疊大小,執行在預設的優先順序上。
執行緒池中有兩種型別的執行緒:IO執行緒和非IO執行緒。IO執行緒等待在可告警狀態,工作專案作為APC放到IO執行緒中。如果你的工作專案需要執行緒執行在可警告狀態,你應該將它放到IO執行緒。
非IO工作者執行緒等待在IO完成埠上,使用非IO執行緒比IO執行緒效率更高,也就是說,只要有可能的話,儘量使用非IO執行緒。IO執行緒和非IO執行緒在非同步IO操作沒有完成之前都不會退出。然而,不要在非IO執行緒中發出需要很長時間才能完成的非同步IO請求。
正確使用執行緒池的方法是,工作專案函式以及它將會呼叫到的所有函式都必須是執行緒池安全的。安全的函式不應該假設執行緒是一次性執行緒的或者是永久執行緒。一般來說,應該避免使用執行緒本地儲存和發出需要永久執行緒的非同步IO呼叫,比如說RegNotifyChangeKeyValue函式。如果需要在永久執行緒中執行這樣的函式的話,可以給QueueUserWorkItem傳遞一個選項WT_EXECUTEINPERSISTENTTHREAD。
注意,執行緒池不能相容COM的單執行緒套間(STA)模型。
為了更深入地講解作業系統實現的執行緒池的優越性,我們首先嚐試著自己實現一個簡單的執行緒池模型。
程式碼如下:
/**//* Test Our own thread pool. */
/**//************************************************************************/
typedef struct _THREAD_POOL
{
HANDLE QuitEvent;
HANDLE WorkItemSemaphore;
LONG WorkItemCount;
LIST_ENTRY WorkItemHeader;
CRITICAL_SECTION WorkItemLock;
LONG ThreadNum;
HANDLE *ThreadsArray;
}THREAD_POOL, *PTHREAD_POOL;
typedef VOID (*WORK_ITEM_PROC)(PVOID Param);
typedef struct _WORK_ITEM
{
LIST_ENTRY List;
WORK_ITEM_PROC UserProc;
}WORK_ITEM, *PWORK_ITEM;
DWORD WINAPI WorkerThread(PVOID pParam)
{
PTHREAD_POOL pThreadPool = (PTHREAD_POOL)pParam;
HANDLE Events[2];
Events[0] = pThreadPool->QuitEvent;
Events[1] = pThreadPool->WorkItemSemaphore;
for(;;)
{
DWORD dwRet = WaitForMultipleObjects(2, Events, FALSE, INFINITE);
if(dwRet == WAIT_OBJECT_0)
break;
//
// execute user's proc.
//
elseif(dwRet == WAIT_OBJECT_0 +1)
{
PWORK_ITEM pWorkItem;
PLIST_ENTRY pList;
EnterCriticalSection(&pThreadPool->WorkItemLock);
_ASSERT(!IsListEmpty(&pThreadPool->WorkItemHeader));
pList = RemoveHeadList(&pThreadPool->WorkItemHeader);
LeaveCriticalSection(&pThreadPool->WorkItemLock);
pWorkItem = CONTAINING_RECORD(pList, WORK_ITEM, List);
pWorkItem->UserProc(pWorkItem->UserParam);
InterlockedDecrement(&pThreadPool->WorkItemCount);
free(pWorkItem);
}
else
{
_ASSERT(0);
break;
}
}
return0;
}
BOOL InitializeThreadPool(PTHREAD_POOL pThreadPool, LONG ThreadNum)
{
pThreadPool->QuitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pThreadPool->WorkItemSemaphore = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
pThreadPool->WorkItemCount =0;
InitializeListHead(&pThreadPool->WorkItemHeader);
InitializeCriticalSection(&pThreadPool->WorkItemLock);
pThreadPool->ThreadNum = ThreadNum;
pThreadPool->ThreadsArray = (HANDLE*)malloc(sizeof(HANDLE) * ThreadNum);
for(int i=0; i<ThreadNum; i++)
{
pThreadPool->ThreadsArray[i] = CreateThread(NULL, 0, WorkerThread, pThreadPool, 0, NULL);
}
return TRUE;
}
VOID DestroyThreadPool(PTHREAD_POOL pThreadPool)
{
SetEvent(pThreadPool->QuitEvent);
for(int i=0; i<pThreadPool->ThreadNum; i++)
{
WaitForSingleObject(pThreadPool->ThreadsArray[i], INFINITE);
CloseHandle(pThreadPool->ThreadsArray[i]);
}
free(pThreadPool->ThreadsArray);
CloseHandle(pThreadPool->QuitEvent);
CloseHandle(pThreadPool->WorkItemSemaphore);
DeleteCriticalSection(&pThreadPool->WorkItemLock);
while(!IsListEmpty(&pThreadPool->WorkItemHeader))
{
PWORK_ITEM pWorkItem;
PLIST_ENTRY pList;
pList = RemoveHeadList(&pThreadPool->WorkItemHeader);
pWorkItem = CONTAINING_RECORD(pList, WORK_ITEM, List);
free(pWorkItem);
}
}
BOOL PostWorkItem(PTHREAD_POOL pThreadPool, WORK_ITEM_PROC UserProc, PVOID UserParam)
{
PWORK_ITEM pWorkItem = (PWORK_ITEM)malloc(sizeof(WORK_ITEM));
if(pWorkItem == NULL)
return FALSE;
pWorkItem->UserProc = UserProc;
pWorkItem->UserParam = UserParam;
EnterCriticalSection(&pThreadPool->WorkItemLock);
InsertTailList(&pThreadPool->WorkItemHeader, &pWorkItem->List);
LeaveCriticalSection(&pThreadPool->WorkItemLock);
InterlockedIncrement(&pThreadPool->WorkItemCount);
ReleaseSemaphore(pThreadPool->WorkItemSemaphore, 1, NULL);
return TRUE;
}
VOID UserProc1(PVOID dwParam)
{
WorkItem(dwParam);
}
void TestSimpleThreadPool(BOOL bWaitMode, LONG ThreadNum)
{
THREAD_POOL ThreadPool;
InitializeThreadPool(&ThreadPool, ThreadNum);
CompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
BeginTime = GetTickCount();
ItemCount =20;
for(int i=0; i<20; i++)
{
PostWorkItem(&ThreadPool, UserProc1, (PVOID)bWaitMode);
}
WaitForSingleObject(CompleteEvent, INFINITE);
CloseHandle(CompleteEvent);
DestroyThreadPool(&ThreadPool);
}
我們把工作專案放到一個佇列中,用一個訊號量通知執行緒池,執行緒池中任意一個執行緒取出工作專案來執行,執行完畢之後,執行緒返回執行緒池,繼續等待新的工作專案。
執行緒池中執行緒的數量是固定的,預先建立好的,永久的執行緒,直到銷燬執行緒池的時候,這些執行緒才會被銷燬。
執行緒池中執行緒獲得工作專案的機會是均等的,隨機的,並沒有特別的方式保證哪一個執行緒具有特殊的優先獲得工作專案的機會。
而且,同一時刻可以併發執行的執行緒數目沒有任何限定。事實上,在我們的執行計算任務的演示程式碼中,所有的執行緒都併發執行。
下面,我們再來看一下,完成同樣的任務,系統提供的執行緒池是如何運作的。
/**//************************************************************************/
相關推薦
VC實現執行緒池
這兩天在做關於網路蜘蛛的程式,希望可以通過執行緒池來提高程式的效能,網上搜索了一下,看到這方面的東西還不少,跟大家分享一下!~有許多應用程式建立的執行緒花費了大量時間在睡眠狀態來等待事件的發生。還有一些執行緒進入睡眠狀態後定期被喚醒以輪詢工作方式來改變或者更新狀態資訊。執行緒池可以
基於C++11實現執行緒池的工作原理.
基於C++11實現執行緒池的工作原理. 文章目錄 基於C++11實現執行緒池的工作原理. 簡介 執行緒池的組成 1、執行緒池管理器 2、工作執行緒 3、任務介面, 4、任務佇列
基於C++11實現執行緒池的工作原理
基於C++11實現執行緒池的工作原理. 不久前寫過一篇執行緒池,那時候剛用C++寫東西不久,很多C++標準庫裡面的東西沒怎麼用,今天基於C++11重新實現了一個執行緒池。 簡介 執行緒池(thread pool):一種執行緒的使用模式,執行緒過多會帶來排程開銷,進而影響快取區域性性和整體效能。而執行緒池
基於C++11 thread 實現執行緒池
轉自:https://blog.csdn.net/u013507368/article/details/48130151 這裡基於C++11 thread實現執行緒池,執行緒池不可拷貝。 1 nocopyable類 不可拷貝基類繼承
使用C++11實現執行緒池的兩種方法
概述:什麼是執行緒池? 因為程式邊執行邊建立執行緒是比較耗時的,所以我們通過池化的思想:在程式開始執行前建立多個執行緒,這樣,程式在執行時,只需要從執行緒池中拿來用就可以了.大大提高了程式執行效率. 如何實現: 一般執行緒池都會有以下幾個部分構成: 1. 執行
使用c語言實現執行緒池以及執行緒池原理
執行緒池介紹 執行緒池允許一個執行緒可以多次複用,且每次複用的執行緒內部的訊息處理可以不相同,將建立與銷燬的開銷省去而不必來一個請求開一個執行緒;簡單來說就是有一堆已經建立好的執行緒(最大數目一定),初始時他們都處於空閒狀態,當有新的任務進來,從執行緒池中取
Spring+TaskExecutor實現執行緒池管理
目錄 目錄 寫在前面 執行緒池引數 程式碼實現 部落格參考 寫在前面 執行緒池可以很好的幫助我們管理執行緒,它會預先建立若干數量的執行緒,並且不能由開發者直接對執行緒的建立進行控制,這樣,消除了頻繁建立和消亡執行緒的系統資源開銷。
c++11實現執行緒池
測試程式 // // main.cpp // #include <iostream> // std::cout, std::endl #include <vector> // std::vector #include <str
執行緒池原理及C語言實現執行緒池
備註:該執行緒池原始碼參考自傳直播客培訓視訊配套資料; 原始碼:https://pan.baidu.com/s/1zWuoE3q0KT5TUjmPKTb1lw 密碼:pp42 引言:執行緒池是一種多執行緒處理形式,大多用於高併發伺服器上,它能合理有效的利用高
【Linux】生產者消費者程式設計實現-執行緒池+訊號量
生產者消費者程式設計實現,採用了執行緒池以及訊號量技術。 執行緒的概念就不多說,首先說一下多執行緒的好處:多執行緒技術主要解決處理器單元內多個執行緒執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。 那麼為什麼又需要執行緒池呢? 我們知道應
如何實現執行緒池的暫停和恢復功能
很多時候我們需要暫停執行緒池,而不是shutdown執行緒池,暫停執行緒池可以為我們儲存任務,稍後可以繼續執行,從而避免不必要的開銷。 這裡我提供一種暫停執行緒池的方法; 首先拿到ThreadPoolExecutor.java原始碼,將其變為自己包內的私有類; 接下來修改執
spring 無配置檔案實現執行緒池管理
最近做一個文件轉換功能比較耗時,所以用到了執行緒池來處理。Spring管理執行緒池有兩種方式,第一種是XML配置檔案配置執行緒池的Bean,然後在用的時候像Controller引用Service的Bean一樣的引用執行緒池物件就可以了。第二種方式是無配置檔案,就是全是java
[C++]C++ 100行實現執行緒池
一個100行左右的簡單執行緒池。用到了std::mutex和std::thread等新特性。 執行緒池模型 首先把每個函式抽象為一個任務(Task),任務的過程就是呼叫這個Task的run函式。 然後把執行緒池中的執行緒封裝為一個執行緒類(Thread),一直等待排程
【原始碼剖析】threadpool —— 基於 pthread 實現的簡單執行緒池
部落格新地址:https://github.com/AngryHacker/articles/issues/1#issue-369867252 執行緒池介紹 執行緒池可以說是專案中經常會用到的元件,在這裡假設讀者都有一定的多執行緒基礎,如果沒有的話不妨在這裡進行了解:POSIX
【Java】執行緒池ThreadPoolExecutor實現原理
引言 執行緒池:可以理解為緩衝區,由於頻繁的建立銷燬執行緒會帶來一定的成本,可以預先建立但不立即銷燬,以共享方式為別人提供服務,一來可以提供效率,再者可以控制執行緒無線擴張。合理利用執行緒池能夠帶來三個好處: 降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造
實現一個執行緒池
1.定義執行緒池 //業務執行緒池 private static final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()
【程式設計筆記】執行緒池實現原始碼(從POCO中剝離出來)
原始碼下載:https://download.csdn.net/download/fzuim/10625204 CThreadPool類 /***************************************************************
如何實現自己的執行緒池(不看後悔,一看必懂)
首先,在服務啟動的時候,我們可以啟動好幾個執行緒,並用一個容器(如執行緒池)來管理這些執行緒。當請求到來時,可以從池中取一個執行緒出來,執行任務(通常是對請求的響應),當任務結束後,再將這個執行緒放入池中備用;如果請求到來而池中沒有空閒的執行緒,該請求需要排隊等候。最後,當服務關閉時銷燬該池即可
執行緒池與cp命令的實現
用Linux C完成shall命令cp的實現 在複製大量檔案時,當遇到大量的或較大的檔案時,使用單程序單執行緒進行檔案複製效率比較低下,而使用執行緒池能很好的提高效率。 思路: 1、初始化執行緒池 2、如果需要複製檔案則直接複製,如果需要複製資料夾則往下 3、遍歷資料夾,複製內容
Java中的執行緒池及其實現類ThreadPoolExecutor
前言:像我們連線資料庫一樣,需要不斷地建立連線,銷燬連線,如果都是人為地一個個建立和銷燬的話會很費勁,所以就誕生了資料庫連線池,執行緒池的產生也是同樣的道理。 執行緒池預先建立了若干數量的執行緒,並且不能由使用者直接對執行緒的建立進行控制,在這個前提下重複使用固定或較為固定數目的執行緒來完成任務