multithreadingwindows-runtimewinrt-asyncwrl

Why is thread pool work item executed on UI thread?


The following code run in a Windows Store app blocks the UI for 30 seconds despite that fact that the loop should run in a separate thread:

int seconds(30);
// Create a thread pool
ComPtr<IThreadPoolStatics> threadPool;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), &threadPool);
//
// Create an asynchronous task and start it
ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncActionPtr;
hr = threadPool->RunAsync(Callback<IWorkItemHandler>( // Line 1
    //
    // Lambda for task. Loops doing nothing until 30 seconds have passed
    [seconds](ABI::Windows::Foundation::IAsyncAction* asyncAction) -> HRESULT {
        std::chrono::system_clock::time_point end(std::chrono::system_clock::now() + std::chrono::seconds(seconds)); // Line 3
        while (std::chrono::system_clock::now() < end);
    return S_OK; // Line 4
}).Get(), &asyncActionPtr);
if (FAILED(hr)) throw std::exception("Cannot start thread"); // Line 2

When I set breakpoints in the marked lines, I can see that Line 1 is hit before Line 2, then Line 3 and after 30 seconds Line 4. In these 30 seconds the UI is blocked and the Thread view in Visual Studio show the same thread (SHcore.dll) for all of the breakpoints. I am using Windows 8 and Visual Studio 2012. Can somebody explain?


Solution

  • Bill Messmer has given the perfect answer on MSDN. In short:

    The delegate object created by Callback is not agile which means that it cannot be passed to the thread pool thread. Instead that thread receives a proxy and calls upon it are marshaled back to the delgate object in the UI thread. Bill has also given an easy fix for the problem.