Boost logo

Boost :

Subject: Re: [boost] [threadpool] new version v12
From: Anthony Williams (anthony.ajw_at_[hidden])
Date: 2008-11-03 06:09:25


"Oliver Kowalke" <k-oli_at_[hidden]> writes:

>> It's OK if the nested task was spawned by this task. If the nested
>> task was spawned by an unrelated task, then these things become real
>> issues.
>
> Sorry I don't know the semantic of an 'urelated task'. Do you mean a
> task created by another worker-thread?

Some (user-level) thread does pool.submit(task1), and another
(user-level) thread does pool.submit(task2). These tasks are
unrelated: one was not spawned by the other. They may also not share
any data: one may be spawned by the GUI thread, and another by a
network thread.
  
>> Also, if your thread runs an unrelated task the condition it was
>> waiting for might become ready, but the task is unable to resume
>> because the new unrelated task is still running. This is why you might
>> choose to migrate fibers between threads:
>>
>> 1. task A spawns tasks B
>> 2. task B gets picked up by other worker threads
>> 3. task N is submitted to the queue, but there are no free workers
>> 4. task A blocks on task B
>> 5. the thread running task A picks up task N
>> 6. task B completes.
>> * task A is now ready to run, but its thread is running task N.
>> * Migrate task A to the thread that just completed task B, and
>> resume task A (easily done with SwitchToFiber). Everything is fine
>> and dandy.... except the thread-local variables and thread ID for
>> task A just changed :-(
>
> I got it. This happens if migration of fibered tasks between
> worker-threads happens.

The problem (changed thread ID) happens if you migrate fibered tasks
between threads once they've started, yes.

That problem was an aside: I was trying to explain why you might do
that in the first place.

> But what about executing fibered tasks only in the worker-thread
> which has created the fiber?

There is still a problem (just different).

> Then a new task is dequeued from the local worker-queue, then from
> the global -queue and then from worker-queues of other threads.

Here's the problem: if you take a task from the global queue or the
worker queue of another thread and *don't* do thread migration, then
you risk delaying a task and potentially deadlocking the pool.

Consider the sequence above: at step 5, task A is blocked, and the
only task it is waiting for (B) has been picked up by an idle worker
thread. The thread running task A now takes a new task from the global
queue (task N). Suppose this is a really long-running task (calculate
PI to 3 million digits, defrag a hard disk, etc.). Without thread
migration, task A cannot resume until task N is complete.

Obviously, if task N blocks on a future you can then reschedule task
A, but if it doesn't then you don't get that opportunity. If task N
waits for another event to be triggered from task A (e.g. a notify on
a condition variable) then it will never get it because task A is
suspended, and so the pool thread will deadlock *even when task A is
ready to run*.

Anthony

-- 
Anthony Williams
Author of C++ Concurrency in Action | http://www.manning.com/williams
Custom Software Development | http://www.justsoftwaresolutions.co.uk
Just Software Solutions Ltd, Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk