[英]Allow start ONLY one thread
我們如何安全地只啟動一個 WorkerThread?
存在它的設計模式嗎?
實際上我是這樣做的,看來我有點過於復雜了。
void CLogView::OnStartStoplogger()
{
m_bLogPtRun = !m_bLogPtRun; // (bool)
if (m_bLogPtRun)
{
// First check, if Thread is still running
if (!m_pLogPointThread)
{
m_pLogPointThread = AfxBeginThread(AddLogPointThread, this);
}
else
return; // Thread still running
}
else
{
if (m_pLogPointThread )
{
if (m_pLogPointThread) {
DWORD dwRET = WaitForSingleObject(m_pLogPointThread->m_hThread, /*INFINITE*/ 5000);
if (dwRET != WAIT_OBJECT_0)
MessageBox(_T("Could not finished LogPointThread"));
}
}
好的,下面是一個示例,假設您創建了一個工作線程,它將一直運行到應用程序退出。 用戶可以暫停和恢復數據檢索和記錄。 如評論中所述,無需為此使用 APC,而是使用同步來控制工作線程。 我提議的同步 object 是manual-reset Event 。 它充當“同步布爾值”,由主 (UI) 線程設置和清除 - 如果未發出信號,工作線程將等待它。
1.變量和初始化
BOOL bInitOK = FALSE; // Worker Thread Successfully Initialized
BOOL bChkRTD = FALSE; // Retrieval & Logging of RTD Enabled
HANDLE m_hEvt = CreateEvent(NULL, TRUE, FALSE, NULL); // Controlling Retrieval & Logging of RTD
CWinThread *m_pLogPointThread = AfxBeginThread(AddLogPointFN, this); // Worker Thread - Created once
請注意,此處的AddLogPointFN
是AFX_THREADPROC
function,而不是 class。這會創建一個沒有消息隊列的線程。 此外,您不需要定義和使用任何線程本地數據(即每個線程實例化的數據),因為線程只實例化一次,即您的數據本質上是“全局的”(盡管它們可能包含在另一個單一實例中class,喜歡主window或查看)。 或者,您可以使用CreateThread()
function 和LPTHREAD_START_ROUTINE
創建您的線程 - 這個是_stdcall
。 事件控制工作線程是否查找數據; 它有點“復制”由用戶設置的bChkRTD
變量 - 事件是可等待的 object,而 boolean 變量不是。
2. 線程程序
UINT AddLogPointFN(LPVOID lParam)
{
// CLogView* variable - For convenience
CLogView* pView = (CLogView*)lParam; // Assuming lParam is CLogView
// Add one-time, resource-heavy initialization here, eg connections
.
.
bool bInit = InitConnections();
if (!bInit)
{
// Initialization Failed - Tell UI to display an error-message or exit
pView->PostMessage(USERMESSAGE_ALPNOTIFY, 1);
return 1;
}
// Initialization Successful - Tell UI to enable RTD request menus or buttons
pView->PostMessage(USERMESSAGE_ALPNOTIFY, 2);
// Wait if m_hEvt is non-signaled
while(WaitForSingleObject(pView->m_hEvt,INFINITE)==WAIT_OBJECT_0)
{
// Retrieve RTD
.
.
// Data retrieved, tell UI to update
pView->PostMessage(USERMESSAGE_ALPNOTIFY, 3, (LPARAM)p_Data);
}
return 0;
}
RTD 檢索通過等待事件 object 來控制。該事件是手動重置的,即等待 function 不會重置它 - 它僅由 UI 線程設置/重置。 線程不會直接修改(全局) bInitOK
變量(這需要同步訪問),而是通知 UI 線程設置它。
3. 主線程項和例程
// Start/Stop Command and UI Update
void CLogView::OnStartStoplogger()
{
bChkRTD = !bChkRTD; // Check-box behavior, see also ON_UPDATE_COMMAND_UI
if (bChkRTD) SetEvent(m_hEvt);
else ResetEvent(m_hEvt);
}
void CLogView::OnUpdateStartStoplogger(CCmdUI *pCmdUI)
{
pCmdUI->Enable(bInitOK); // Enabled if Initialization Successful
pCmdUI->SetCheck(bChkRTD); // Checked if RTD Retrieval Enabled
}
// USERMESSAGE_ALPNOTIFY Handler
afx_msg LRESULT CLogView::OnALPNotify(WPARAM wParam, LPARAM lParam)
{
switch(wParam)
{
case 1: // Initialization Failed - Show some message or exit
.
.
break;
case 2: // Initialization Successful - Enable Start/Stop UI item
bInitOK = TRUE;
break;
case 3: // New RTD Available - Display the data
// E.g. copy the date returned from the worker thread to some local structure
CopyMyData(m_pMyData, (MY_DATA*)lParam);
GlobalFree((HGLOBAL)lParam)
UpdateData(FALSE);
break;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.