воскресенье, 22 ноября 2015 г.

Pitfall of TaskCreationOptions.LongRunning

Recently I had conversation with colleague about using TaskCreationOptions.LongRunning for task which pings another service every N seconds till the end of application lifetime. Fortunately just a few days before I glanced over default task scheduler implementation in Reflector:

[SecurityCritical]
protected internal override void QueueTask(Task task)
{
    if ((task.Options & TaskCreationOptions.LongRunning) != TaskCreationOptions.None)
    {
        new Thread(s_longRunningThreadWork) { IsBackground = true }.Start(task);
    }
    else
    {
        bool forceGlobal = (task.Options & TaskCreationOptions.PreferFairness) != TaskCreationOptions.None;
        ThreadPool.UnsafeQueueCustomWorkItem(task, forceGlobal);
    }
}


The thing that catch my attention was the way dedicated thread is created. So I built small demo and it immediately confirmed that so called long-running task on default thread-pool scheduler uses dedicated thread only until it encounters first await. Afterwards it releases ‘dedicated’ thread and uses thread-pool threads to execute it’s continuation block, same thread-pool threads which are used by other tasks.
Wider Two Column Modification courtesy of The Blogger Guide