null values in List<string> when adding and removing in multiple threads

Viewed 496

I know the C# System.Collections.Generic.List object is not thread safe. But I am wondering why this piece of code generates null values.

Task.Run(() =>
{
    for (var i = 0; i < 10; i++)
    {
        var str = $"Test {i}";
        list.Add(str);

        if (i == 9)
        {
            i = 0;
        }
    }
});

Task.Run(() =>
{
    while (true)
    {
        list.Remove("Test 1");
        list.Remove("Test 2");
        list.Remove("Test 3");
        list.Remove("Test 4");
        list.Remove("Test 5");
        list.Remove("Test 6");
        list.Remove("Test 7");
        list.Remove("Test 8");
        list.Remove("Test 9");
    }
});

This is a part of the list after some seconds:

enter image description here

The thread which is responsible to remove the entries from the list can crash, if the entry is not present in the list. Therefore and for other multithreading reasons I understand why some objects are not removed from the list, but I do not understand how these null values are generated. Has anyone an explanation how these values are generated?

2 Answers

List<T> is not thread-safe except for N reads and zero writes; any non-zero number of writes alongside anything else is not supported, and such behavior is completely undefined. If you need concurrency: either add synchronization, or use a concurrent collection type.

in addition to @Marc Gravell answer.

but I do not understand how these null values are generated

The first thread continuously adds "Test {i}". However, the next thread removes "Test {i}". Therefore, Those null values are as a result of removal action of the next thread.

of worth to say that, next "Test {i}" won't be replaced to removed one but appended at the end of the generic collection.

The final result would behave like below:

Test 1 null Test 3 null null Test 6 .... Test 1 Test 2 null null Test 6 ...  
Related