线程池函数1 - 异步调用函数
来源:互联网 发布:pg数据库substring 编辑:程序博客网 时间:2024/05/05 10:18
本次主要针对默认线程池。
//1)使用TrySubmitThreadpoolCallback//注意每次调用TrySubmitThreadpoolCallback,//系统都会分配一个工作项work item。//所以如果打算提交大量的工作项,出于性能和内存的考虑,//最好使用下面另一组函数。/*调用TrySubmitThreadpoolCallback,系统会自动分配work item,该函数通过PostQueuedCompletionStatus将该work item添加到线程池队列中,线程池也由系统创建,并让线程池中的一个线程来调用我们的回调函数,当这个线程处理完一个客户请求之后,它并不会立刻被销毁,而是回到线程池,准备好处理队列中的任何其它的工作项。*///默认线程池,不用考虑后两个参数,定制时才需要BOOL WINAPI TrySubmitThreadpoolCallback( _In_ PTP_SIMPLE_CALLBACK pfns, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe);//默认线程池,不用考虑参数,定制时才需要VOID CALLBACK SimpleCallback( _Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context);//2)先用CreateThreadpoolWork创建一个工作项,//然后使用同一个work item来调用SubmitThreadpoolWork提交多个请求PTP_WORK WINAPI CreateThreadpoolWork( _In_ PTP_WORK_CALLBACK pfnwk, _Inout_opt_ PVOID pv, _In_opt_ PTP_CALLBACK_ENVIRON pcbe);VOID CALLBACK WorkCallback( _Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context, _Inout_ PTP_WORK Work);VOID WINAPI SubmitThreadpoolWork( _Inout_ PTP_WORK pwk);VOID WINAPI WaitForThreadpoolWorkCallbacks( _Inout_ PTP_WORK pwk, _In_ BOOL fCancelPendingCallbacks);VOID WINAPI CloseThreadpoolWork( _Inout_ PTP_WORK pwk);
1.创建work object, 所有task共用
PTP_WORK WINAPI CreateThreadpoolWork( _In_ PTP_WORK_CALLBACK pfnwk, //回调函数 _Inout_opt_ PVOID pv, //传给回调函数的参数 _In_opt_ PTP_CALLBACK_ENVIRON pcbe //回调函数执行环境);
2.定义异步执行的回调函数
Applications implement this callback if they call the SubmitThreadpoolWork
function to start a worker thread for the work object.
VOID CALLBACK WorkCallback( _Inout_ PTP_CALLBACK_INSTANCE Instance, _Inout_opt_ PVOID Context, _Inout_ PTP_WORK Work);
3.向线程池提交work请求
系统会自动创建一个默认的线程池,并让线程池中的一个线程来调用我们的回调函数
Posts a work object to the thread pool. A worker thread calls the work object’s callback function.
VOID WINAPI SubmitThreadpoolWork( _Inout_ PTP_WORK pwk //created by CreateThreadpoolWork);
4.等待未完成的callback完成,同时可以取消pending的callback被执行
Waits for outstanding work callbacks to complete and optionally
cancels pending callbacks that have not yet started to execute.
VOID WINAPI WaitForThreadpoolWorkCallbacks(_Inout_ PTP_WORK pwk,_In_ BOOL fCancelPendingCallbacks);
5.释放work object
Releases the specified work object.
The work object is freed immediately if there are no outstanding callbacks;
otherwise, the work object is freed asynchronously after the outstanding callbacks complete.
If there is a cleanup group associated with the work object, it is not necessary to call this function;
calling the CloseThreadpoolCleanupGroupMembers function releases the work, wait, and timer objects associated with the cleanup group.
VOID WINAPI CloseThreadpoolWork( _Inout_ PTP_WORK pwk //created by CreateThreadpoolWork);
6.实例1
下面的代码是按上面的2)来设计的
BatchDlg.hclass CBatchDlg : public CDialogEx{... ...protected: virtual BOOL OnInitDialog(); afx_msg void OnBnClickedOk(); afx_msg void OnDestroy(); afx_msg LRESULT OnCompleted(WPARAM wParam, LPARAM lParam);private: BOOL CreateWorkObject(); BOOL SubmitWorkToThreadPool(); void WaitCloseThreadPool(); static void CALLBACK TaskHandler(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work);private: CListBox m_oLstBox; PTP_WORK m_pWorkItem;};BatchDlg.cpp#include <strsafe.h>#include <Windowsx.h>#define WM_APP_COMPLETED (WM_APP+123)HWND g_hDlg = nullptr;volatile LONG g_nCurrentTask = 0;void AddMessage(LPCTSTR szMsg) { HWND hListBox = GetDlgItem(g_hDlg, IDC_LIST1); ListBox_SetCurSel(hListBox, ListBox_AddString(hListBox, szMsg));}BOOL CBatchDlg::OnInitDialog(){ ... ... g_hDlg = m_hWnd; BOOL bRet = CreateWorkObject(); ASSERT(bRet);}void CBatchDlg::OnBnClickedOk(){ BOOL bRet = SubmitWorkToThreadPool(); ASSERT(bRet);}LRESULT CBatchDlg::OnCompleted(WPARAM wParam, LPARAM lParam){ TCHAR szMsg[MAX_PATH + 1]; StringCchPrintf( szMsg, _countof(szMsg), TEXT("____Task #%u was the last task of the batch____"), lParam); AddMessage(szMsg); ::Button_Enable(::GetDlgItem(m_hWnd, IDOK), TRUE); return 0;}//-------------------关键代码如下-------------------//1.创建work objectBOOL CBatchDlg::CreateWorkObject(){ ASSERT(nullptr == m_pWorkItem); // Create the work item that will be used by all tasks m_pWorkItem = CreateThreadpoolWork(TaskHandler, NULL, NULL); if (m_pWorkItem == nullptr) { ::MessageBox(NULL, TEXT("Impossible to create the work item for tasks."), TEXT(""), MB_ICONSTOP); return FALSE; } return TRUE;}//2.定义异步执行的回调函数void CALLBACK CBatchDlg::TaskHandler(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work){ LONG currentTask = InterlockedIncrement(&g_nCurrentTask); TCHAR szMsg[MAX_PATH]; StringCchPrintf(szMsg, _countof(szMsg), TEXT("[%u] Task #%u is starting."), GetCurrentThreadId(), currentTask); AddMessage(szMsg); // Simulate a lot of work Sleep(currentTask * 1000); StringCchPrintf(szMsg, _countof(szMsg), TEXT("[%u] Task #%u is done."), GetCurrentThreadId(), currentTask); AddMessage(szMsg); if (InterlockedDecrement(&g_nCurrentTask) == 0) { // Notify the UI thread for completion. ::PostMessage(g_hDlg, WM_APP_COMPLETED, 0, (LPARAM)currentTask); }}//3.向线程池提交work请求BOOL CBatchDlg::SubmitWorkToThreadPool(){ if (m_pWorkItem == nullptr) { ::MessageBox(NULL, TEXT("Impossible to create the work item for tasks."), TEXT(""), MB_ICONSTOP); return FALSE; } ::Button_Enable(::GetDlgItem(g_hDlg, IDOK), FALSE); AddMessage(TEXT("----Start a new batch----")); // Submit 4 tasks by using the same work item SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem); AddMessage(TEXT("4 tasks are submitted.")); return TRUE;}//4,5.释放work objectvoid CBatchDlg::WaitCloseThreadPool(){ if (m_pWorkItem == nullptr) return; //WaitForThreadpoolWorkCallbacks(m_pWorkItem, TRUE); CloseThreadpoolWork(m_pWorkItem);}
7.实例2
7.1 MyObj .h/cpp,CMyObj 类,线程池函数要处理的对象
class CMyObj : public CObject{public: CMyObj(const CString& strName, int nNum, CListBox& lstBox); virtual ~CMyObj();public: BOOL DoSth(); BOOL IsDone()const;protected: void AddMsg(const CString& strMsg);protected: CListBox& m_lstBox; CString m_strName; int m_nNum; BOOL m_bIsDone;};// CMyObjCMyObj::CMyObj(const CString& strName, int nNum, CListBox& lstBox) : m_nNum(nNum) , m_lstBox(lstBox) , m_strName(strName) , m_bIsDone(FALSE){}CMyObj::~CMyObj(){ TRACE(_T("[%s] is released\n"), m_strName);}// CMyObj member functionsBOOL CMyObj::DoSth(){ CString strMsg; for (int i = 0; i < m_nNum; ++i) { strMsg.Format(_T("%s, %04d, %p, threadId=%u"), m_strName, i, this, GetCurrentThreadId()); AddMsg(strMsg); Sleep(500); } m_bIsDone = TRUE; return TRUE;}BOOL CMyObj::IsDone()const{ return m_bIsDone;}void CMyObj::AddMsg(const CString& strMsg){ m_lstBox.AddString(strMsg);}
7.2 ObjManager.h/cpp, CObjManager管理CMyObj对象
class CMyObj;class CObjManager{public: CObjManager(); ~CObjManager(); //clean void CleanCompleteObj(); void ReleaseAll(); //create object void AddObjToBacklogList(const CString& strName, int nNum, CListBox& lstbox); void SetCreating(BOOL bCreate); BOOL IsCreating()const; //handle object void SetRunning(BOOL bRun); BOOL IsRunning()const; BOOL HandleOneObj(); void AddObjToWorkingList(CObject* obj);private: CObList m_oBacklogList; CCriticalSection m_csBacklogList; BOOL m_bIsCreating; // CObList m_oWorkingList; CCriticalSection m_csWorkingList; BOOL m_bIsRunning;};CObjManager::CObjManager() : m_bIsRunning(FALSE) , m_bIsCreating(FALSE){}CObjManager::~CObjManager(){ ReleaseAll();}//控制是否继续往链表里面添加待处理对象void CObjManager::SetCreating(BOOL bCreate){ m_bIsCreating = bCreate;}BOOL CObjManager::IsCreating()const{ return m_bIsCreating;}//控制是否继续处理链表中的待处理项void CObjManager::SetRunning(BOOL bRun){ m_bIsRunning = bRun;}BOOL CObjManager::IsRunning()const{ return m_bIsRunning;}//新增加一个待处理对象,放入backlog列表void CObjManager::AddObjToBacklogList(const CString& strName, int nNum, CListBox& lstbox){ CSingleLock sLock(&m_csBacklogList, TRUE); CMyObj* pObj = new CMyObj(strName, nNum, lstbox); if (nullptr != pObj) { POSITION pos = m_oBacklogList.AddTail(pObj); ASSERT(pos); }}//从backlog列表中拿一个对象,放入working列表,并开始处理这个对象BOOL CObjManager::HandleOneObj(){ POSITION pos = nullptr; CMyObj* pObj = nullptr; { CSingleLock sLock(&m_csBacklogList, TRUE); pos = m_oBacklogList.GetHeadPosition(); if (pos == nullptr) return FALSE; pObj = (CMyObj*)m_oBacklogList.GetAt(pos); m_oBacklogList.RemoveAt(pos); AddObjToWorkingList(pObj); } if (nullptr != pObj) pObj->DoSth(); return TRUE;}//把对象放入working列表void CObjManager::AddObjToWorkingList(CObject* obj){ if (nullptr == obj) return; CSingleLock sLock(&m_csWorkingList, TRUE); POSITION pos = m_oWorkingList.AddTail(obj); ASSERT(pos);}void CObjManager::CleanCompleteObj(){ CMyObj* pObj = nullptr; POSITION pos = nullptr, posPre = nullptr; CSingleLock oLock(&m_csWorkingList, TRUE); for (pos = m_oWorkingList.GetHeadPosition(); (posPre = pos) != nullptr;) { if (!IsRunning()) break; pObj = (CMyObj*)m_oWorkingList.GetNext(pos); if (nullptr == pObj) { m_oWorkingList.RemoveAt(posPre); } else if (pObj->IsDone()) { m_oWorkingList.RemoveAt(posPre); delete pObj; } }}void CObjManager::ReleaseAll(){ CObject* pObj = nullptr; POSITION pos = nullptr; { CSingleLock sLock(&m_csBacklogList, TRUE); for (pos = m_oBacklogList.GetHeadPosition(); pos != nullptr;) { pObj = m_oBacklogList.GetNext(pos); if (nullptr == pObj) continue; delete pObj; } m_oBacklogList.RemoveAll(); } // { CSingleLock oLock(&m_csWorkingList, TRUE); for (pos = m_oWorkingList.GetHeadPosition(); pos != nullptr;) { pObj = m_oWorkingList.GetNext(pos); if (nullptr == pObj) continue; delete pObj; } m_oWorkingList.RemoveAll(); }}
7.3 对话框类
// CBatchDlg dialogclass CBatchDlg : public CDialogEx{... ...protected: virtual BOOL OnInitDialog(); afx_msg void OnDestroy(); afx_msg void OnBnClickedOk(); afx_msg void OnBnClickedBtnHandleObj();public: void CloseCreatObjThread(); void CloseCleanObjThread();private: BOOL CreateWorkObject(); void SubmitWorkToThreadPool(); void WaitCloseThreadPool(); static void CALLBACK TaskHandler(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work); static DWORD WINAPI CreateObjThread(LPVOID lpParam); static DWORD WINAPI CleanObjThread(LPVOID lpParam);public: CListBox m_oLstBox;//输出信息 static CObjManager m_objMgr; //管理所有要处理的对象private: PTP_WORK m_pWorkItem;//线程池对象 HANDLE m_hCreatObjThread;//创建要处理对象的线程 HANDLE m_hCleanObjThread;//清理完成处理的对象};CObjManager CBatchDlg::m_objMgr;CBatchDlg::CBatchDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_BATCH_DIALOG, pParent) , m_pWorkItem(nullptr) , m_hCreatObjThread(nullptr) , m_hCleanObjThread(nullptr){ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}BEGIN_MESSAGE_MAP(CBatchDlg, CDialogEx) ON_WM_DESTROY() ON_BN_CLICKED(IDOK, &CBatchDlg::OnBnClickedOk) ON_BN_CLICKED(IDC_BTN_HANDLE_OBJ, &CBatchDlg::OnBnClickedBtnHandleObj)END_MESSAGE_MAP()//1.定义线程池的线程函数(异步执行的回调函数)void CALLBACK CBatchDlg::TaskHandler(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work){ while (m_objMgr.IsRunning()) { if (!m_objMgr.HandleOneObj()) Sleep(10); } TRACE(_T("Exit Thread CBatchDlg::TaskHandler: id = %x\n"), GetCurrentThreadId());}//2.创建work objectBOOL CBatchDlg::OnInitDialog(){ CDialogEx::OnInitDialog(); SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); //2.创建work object BOOL bRet = CreateWorkObject(); ASSERT(bRet); return TRUE; // return TRUE unless you set the focus to a control}//2.创建work objectBOOL CBatchDlg::CreateWorkObject(){ ASSERT(nullptr == m_pWorkItem); // Create the work item that will be used by all tasks m_pWorkItem = CreateThreadpoolWork(TaskHandler, NULL, NULL); if (m_pWorkItem == nullptr) { ::MessageBox(NULL, TEXT("Impossible to create the work item for tasks."), TEXT(""), MB_ICONSTOP); return FALSE; } return TRUE;}//3.创建“生产者”线程,不断的创建待处理对象void CBatchDlg::OnBnClickedOk(){ if (m_hCreatObjThread) { m_objMgr.SetCreating(FALSE); SetDlgItemText(IDOK, _T("Start Create")); return; } m_objMgr.SetCreating(TRUE); m_hCreatObjThread = CreateThread( NULL, // default security attributes 0, // use default stack size CreateObjThread, // thread function name this, // argument to thread function 0, // use default creation flags NULL); // returns the thread identifier if (NULL == m_hCreatObjThread) { m_objMgr.SetCreating(FALSE); SetDlgItemText(IDOK, _T("Start Create")); } else { SetDlgItemText(IDOK, _T("Stop Create")); }}DWORD WINAPI CBatchDlg::CreateObjThread(LPVOID lpParam){ CBatchDlg* pThis = (CBatchDlg*)lpParam; if (nullptr == pThis) return 0; static LONG lCount = 0; CString strName(_T("")); while (m_objMgr.IsCreating()) { ++lCount; strName.Format(_T("Obj[%ld]"), lCount); m_objMgr.AddObjToBacklogList(strName, 10, pThis->m_oLstBox); Sleep(1000); } pThis->CloseCreatObjThread(); TRACE(_T("Exit Thread CBatchDlg::CreateObjThread\n")); return 0;}void CBatchDlg::CloseCreatObjThread(){ if (nullptr != m_hCreatObjThread) { CloseHandle(m_hCreatObjThread); m_hCreatObjThread = nullptr; }}//4.创建清理线程,向线程池提交work请求void CBatchDlg::OnBnClickedBtnHandleObj(){ if (nullptr == m_hCleanObjThread) { m_hCleanObjThread = CreateThread( NULL, // default security attributes 0, // use default stack size CleanObjThread, // thread function name NULL, // argument to thread function 0, // use default creation flags NULL); // returns the thread identifier } if (m_objMgr.IsRunning()) { m_objMgr.SetRunning(FALSE); Sleep(3000);//等待线程池中的线程退出 SetDlgItemText(IDC_BTN_HANDLE_OBJ, _T("Start Work")); return; } m_objMgr.SetRunning(TRUE); SubmitWorkToThreadPool(); SetDlgItemText(IDC_BTN_HANDLE_OBJ, _T("Stop Work"));}void CBatchDlg::SubmitWorkToThreadPool(){ SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem); SubmitThreadpoolWork(m_pWorkItem);}DWORD WINAPI CBatchDlg::CleanObjThread(LPVOID lpParam){ while (m_objMgr.IsRunning()) { m_objMgr.CleanCompleteObj(); Sleep(1000); } TRACE(_T("Exit Thread CBatchDlg::CleanObjThread\n")); return 0;}void CBatchDlg::CloseCleanObjThread(){ if (nullptr != m_hCleanObjThread) { CloseHandle(m_hCleanObjThread); m_hCleanObjThread = nullptr; }}//5. 释放“生产者”线程,等待线程池线程结束,释放线程池work objectvoid CBatchDlg::OnDestroy(){ m_objMgr.SetRunning(FALSE); m_objMgr.SetCreating(FALSE); Sleep(3000); CloseCreatObjThread(); CloseCleanObjThread(); WaitCloseThreadPool(); CDialogEx::OnDestroy();}//5.释放work objectvoid CBatchDlg::WaitCloseThreadPool(){ if (m_pWorkItem == nullptr) return; //WaitForThreadpoolWorkCallbacks(m_pWorkItem, FALSE); //WaitForThreadpoolWorkCallbacks(m_pWorkItem, TRUE); CloseThreadpoolWork(m_pWorkItem);}
8. 待解决问题 WaitForThreadpoolWorkCallbacks 导致失去响应
据说 devenv.exe /safemode运行就不会出这个现象,但试了不行。
- 线程池函数1 - 异步调用函数
- Chapter11-"windows线程池"之异步调用函数
- atl异步线程调用js函数
- 异步调用函数
- 异步函数调用 犯错
- 进程,线程,函数调用
- 线程调用成员函数
- SAP 函数的异步调用
- 使用libuv线程池实现Node.js异步函数
- 可重入函数、线程安全函数、异步信号安全函数
- C#线程函数调用方式
- 两个线程调用同一个函数
- QT线程调用界面函数
- linux线程调度函数调用
- 线程函数能调用成员函数吗?
- 成员函数作为线程函数调用
- 成员函数作为线程函数调用
- 多个线程调用同一个线程函数
- Unity5的AssetBundle系统在mmo中的使用经验
- AlertDialog的简单实用
- Lambda表达式
- PAT甲级.1027. Colors in Mars (20)
- sdut oj2140 图结构练习——判断给定图是否存在合法拓扑序列
- 线程池函数1 - 异步调用函数
- dubbo测试搭建 --- 使用maven设计模块(二)
- 多线程——等待-唤醒机制的优化
- android 验证码之短信验证(云之讯短信平台)
- C++中const的本质
- dubbo 搭建 引入相应的jar文件(三)
- 用 webView 加载 html 字符串代码来显示图片
- 集合框架_03_List集合之Vector(线程安全)
- SDUT OJ 3363 数据结构实验之图论七:驴友计划