Terminate threads in the PPL thread pool

598 Views Asked by At

Microsoft's PPL library contains powerful parallelisation concepts, and implements them using a thread pool, so no new threads are normally created when running PPL tasks. However, there doesn't seem to be a way to explicitly stop the threads in the thread pool.

The reason why I want to explicitly stop the threads is because of Qt. Some Qt methods store information in an allocated class instance, and a pointer to this class instance is stored in thread-local storage. This memory is only cleaned up if threads are stopped in a graceful way. If not, Qt cannot clean up this allocated memory.

Combining PPL with Qt implies that this memory is not decently deallocated at exit, which is not a problem in itself, but unfortunately this non-deallocated memory is reported as a memory leak by our memory allocation library (see Is anyone using valgrind and Qt? for a similar problem).

We noticed that if we create threads ourself (so not using the PPL thread pool), no leaks are reported. If we use PPL, leaks are reported.

So, the question: is there a way to explicitly stop the threads in the PPL thread pool?

1

There are 1 best solutions below

11
Bernd On

The PPL follows very much the same concept in C++ like async programming in C#.

The general idea is "cooperative cancelation" - you can ask a thread to stop, the thread decides when it is possible to cancel. You should not kill tasks/threads so that a thread is not stopped at an undefined instruction.

Here you can see a sample how to stop a thread / task with ppl:

include <ppltasks.h>
#include <concrt.h>
#include <iostream>
#include <sstream>

using namespace concurrency;
using namespace std;

bool do_work()
{
    // Simulate work.
    wcout << L"Performing work..." << endl;
    wait(250);
    return true;
}

int wmain()
{
    cancellation_token_source cts;
    auto token = cts.get_token(); // <-- allow early cancellation, therefore share a cancellation_token

    wcout << L"Creating task..." << endl;

    // Create a task that performs work until it is canceled.
    auto t = create_task([&]
    {
        bool moreToDo = true;
        while (moreToDo)
        {
            // Check for cancellation.
            if (token.is_canceled()) //<-- check for cancellation in the background thread
            {
                // Cancel the current task.
                cancel_current_task(); //<-- informs the caller, "hey I got it..."
            }
            else 
            {
                // Perform work.
                moreToDo = do_work();
            }
        }
    }, token);

    // Wait for one second and then cancel the task.
    wait(1000);

    wcout << L"Canceling task..." << endl;
    cts.cancel();

    // Wait for the task to cancel.
    wcout << L"Waiting for task to complete..." << endl;

    t.wait(); //<-- this is import

    wcout << L"Done." << endl;
}

But to help you more - can you provide us some source code?