簡體   English   中英

只允許啟動一個線程

[英]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

請注意,此處的AddLogPointFNAFX_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM