Strange appearance of a null entry in the list of tasks

浪尽此生 提交于 2019-12-22 15:05:31

问题


Here is the code involved:

private static async Task DoRunInOrderAsync<TTaskSeed>(SemaphoreSlim sem, IObservable<TTaskSeed> taskSeedSource, CreateTaskDelegate<TTaskSeed> createTask, OnTaskErrorDelegate<TTaskSeed> onFailed, OnTaskSuccessDelegate<TTaskSeed> onSuccess) where TTaskSeed : class
{
    var tasks = await taskSeedSource
        .Select(taskSeed => GetPendingOrRunningTask(taskSeed, createTask, onFailed, onSuccess, sem))
        .ToList()
        .ToTask();

    await Task.WhenAll(tasks);
}
private static async Task GetPendingOrRunningTask<T>(T taskSeed, CreateTaskDelegate<T> createTask, OnTaskErrorDelegate<T> onFailed, OnTaskSuccessDelegate<T> onSuccess,
    SemaphoreSlim sem) where T : class
{
    Exception exc = null;
    await sem.WaitAsync();
    try
    {
        var task = createTask(taskSeed);
        if (task != null)
        {
            await task;
        }
        onSuccess(task, taskSeed);
    }
    catch (Exception e)
    {
        exc = e;
    }

    sem.Release();

    if (exc != null)
    {
        onFailed(exc, taskSeed);
    }
}

Where:

  • Select is IObservable<TResult> Select<TSource, TResult>(this IObservable<TSource> source, Func<TSource, TResult> selector) from System.Reactive.Linq.Observable
  • ToList is IObservable<IList<TSource>> ToList<TSource>(this IObservable<TSource> source) from System.Reactive.Linq.Observable
  • ToTask is Task<TResult> ToTask<TResult>(this IObservable<TResult> observable) from System.Reactive.Threading.Tasks.TaskObservableExtensions
  • System.Reactive.Linq version is 2.2.5.0

As far as I can see, everything is built, no stale binaries around. The error occurs often, but not always.

For the life of me, I cannot understand how the tasks list can contain null if the GetPendingOrRunningTask method is async Task ?

EDIT

So ToList injects null. How? Why? What am I doing wrong (besides programming for a living) ?


回答1:


You may have a race condition.

.ToList() calls the List<T> constructor. The code is here.

If the number of elements in your taskSeedSource changes between the time the constructor starts and finishes, it's possible that you could end up with an inconsistent list. In particular look at line 94.

ICollection<T> c = collection as ICollection<T>;
if( c != null) {
    int count = c.Count;
    if (count == 0)
    {
        _items = _emptyArray;
    }
    else {
        _items = new T[count];
        c.CopyTo(_items, 0);  /* it's possible there are now fewer elements in c */
        _size = count;
    }
} 


来源:https://stackoverflow.com/questions/27412560/strange-appearance-of-a-null-entry-in-the-list-of-tasks

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!