1

I am trying to start a worker thread using AfxBeginThread and wait until it finished. But I run into the issue, that I can either update the UI (show progress) without the thread conrol or wait for the thread but the UI freezes. I found out several approaches for getting the completion but they all use WaitForSingleObject. Is there any other solution for this? Here is my example code:

UINT CProgressBarSampleDlg::MyControllingFunction(LPVOID pParam)
{
    CProgressBarSampleDlg* pObject = (CProgressBarSampleDlg*)pParam;

    for (size_t i = 0; i < 10; i++)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // simulate long running operation
        
        pObject->m_ProgressBar.StepIt(); // update progress
    }
    
    return 0;
}

void CProgressBarSampleDlg::OnBtnStartClicked()
{
    auto thread = AfxBeginThread(MyControllingFunction, this);
    
    // ... this freezes the UI!
    thread->m_bAutoDelete = FALSE;
    WaitForSingleObject(thread->m_hThread, INFINITE);
    delete thread;
}
alex555
  • 1,676
  • 4
  • 27
  • 45
  • 4
    Don't wait - post a message (from the worker thread) to your main window (UI thread) when the background task completes and the results are ready for collection. – Richard Critten Aug 13 '20 at 09:25
  • 1
    `delete thread;` - you do double delete here. after `MyControllingFunction` exit - `AfxEndThread` will be called with `bDelete = TRUE` as result `CWinThread::Delete()` will be called and if you not set `m_bAutoDelete` to false - will be again delete called – RbMm Aug 13 '20 at 10:51
  • really you can create pure win32 thread and pass to it *hwnd* of your window. periodically post to your window some messages, instead call `StepIt()` (this call must be in UI thread on message) – RbMm Aug 13 '20 at 12:16

1 Answers1

0

Well, with Richard's suggestion I solved it this way. Also, the progress bar access was moved into the message handler.

UINT CProgressBarSampleDlg::MyControllingFunction(LPVOID pParam)
{
    CProgressBarSampleDlg* pObject = (CProgressBarSampleDlg*)pParam;

    pObject->SendMessage(WM_THREAD_1, 0, (LPARAM)1);
    for (size_t i = 0; i < 10; i++)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // simulate long running operation            
        pObject->SendMessage(WM_THREAD_1, 0, (LPARAM)2);
    }
    
    pObject->SendMessage(WM_THREAD_1, 0, (LPARAM)3);
    return 0;
}


void CProgressBarSampleDlg::OnBtnStartClicked()
{
    AfxBeginThread(MyControllingFunction, this);
}

Thanks for your ideas

alex555
  • 1,676
  • 4
  • 27
  • 45