多个线程向一个列表添加元素.为什么列表中的项目总是比预期的少? [英] multiple threads adding elements to one list. why are there always fewer items in the list than expected?

查看:33
本文介绍了多个线程向一个列表添加元素.为什么列表中的项目总是比预期的少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码解释了我的问题.我知道该列表不是线程安全的.但这背后的真实"原因是什么?

The following code explains my question. I know the list is not thread safe. But what is the underlying "real" reason of this?

    class Program
{
    static void Main(string[] args)
    {
        List<string> strCol = new List<string>();

        for (int i = 0; i < 10; i++)
        {
            int id = i;
            Task.Factory.StartNew(() =>
            {
                AddElements(strCol);
            }).ContinueWith((t) => { WriteCount(strCol, id.ToString()); });
        }

        Console.ReadLine();
    }

    private static void WriteCount(List<string> strCol, string id)
    {
        Console.WriteLine(string.Format("Task {0} is done. Count: {1}. Thread ID: {2}", id, strCol.Count, Thread.CurrentThread.ManagedThreadId));
    }

    private static void AddElements(List<string> strCol)
    {
        for (int i = 0; i < 20000; i++)
        {
            strCol.Add(i.ToString());
        }
    }
}

推荐答案

我将跳过明显的答案列表不是线程安全的"——你已经知道了.

I will skip the obvious answer "List is not thread safe" - this you already know.

列表项保存在一个内部数组中.将项目添加到列表时,至少有两个阶段(从逻辑的角度来看).首先,List 获取一个索引,指示放置新项目的位置.它使用此索引将新项目放入数组.然后它增加索引,这是第二阶段.如果第二个(或第三个,第四个,...)线程同时添加新项目,则可能会有两个(3, 4,...)新项目放入索引之前的相同数组位置由第一个线程递增.项目被覆盖并丢失.

List items are kept in an internal array. There are at least two stages (from logical point of view) when adding an item to a List. First, List gets an index indicating where to put new item. It puts new item into array using this index. Then it increments the index and this is stage two. If second (or third, forth, ...) thread happens to add new item at the same time it may be that there will be two (3, 4, ...) new items put into the same array location before the index is incremented by the first thread. Items are overwritten and lost.

添加新项目和增加索引的内部操作必须总是一次性完成,以便列表是线程安全的.这就是所谓的临界区.这可以通过锁来实现.

The internal operations of adding new item and incrementing index must be always done in one go for the list to be thread safe. That's what is called critical section. This can be achieved by locks.

希望这能解释一下.

这篇关于多个线程向一个列表添加元素.为什么列表中的项目总是比预期的少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆