从线程更新的集合中获取对象列表

发布于 2024-10-11 17:09:20 字数 598 浏览 4 评论 0原文

我有一个线程正在更新的项目字典。我想要一个方法使用另一个线程获取更新的项目列表。

像这样:

    internal List<string> GetListOfEntities()
    {            
        List<string> listOfEntities = new List<string>();
        foreach (string entityName in ModelFacade._totalListOfStkObjects.Keys)
        {
            listOfEntities.Add(entityName);
        }
        return listOfEntities;
    }

ModelFacade._totalListOfStkObjects 是线程正在更新的集合。我不断收到异常:“集合已修改;枚举操作可能无法执行。”;我尝试将 _totalListOfStkObjects 复制到本地集合并在 GetListOfEntities() 中迭代它..但我得到了相同的错误..?

有什么帮助吗?

沃夫加Pro

I have a Dictionary of items that a thread is updating. I want to have a method get the updated list of items using another thread.

Like so:

    internal List<string> GetListOfEntities()
    {            
        List<string> listOfEntities = new List<string>();
        foreach (string entityName in ModelFacade._totalListOfStkObjects.Keys)
        {
            listOfEntities.Add(entityName);
        }
        return listOfEntities;
    }

ModelFacade._totalListOfStkObjects is the collection being updated by the thread. I keep getting the exception: "Collection was modified; enumeration operation may not execute."; I have tried copying _totalListOfStkObjects to a local collection and iterating over that in GetListOfEntities().. but I get the same error..?

Any help ?

WulfgarPro

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

烙印 2024-10-18 17:09:20

不会有保证线程安全的方式来访问字典。最好的选择是更改代码,以便不共享集合,或者在访问时锁定字典:

object dictLock = new object();

internal List<string> GetListOfEntities()
{            
    lock (dictLock)
    {
        return ModelFacade._totalListOfStkObjects.Keys.ToList();
    }
}

确保在另一个线程中修改字典时也锁定字典。

There isn't going to be a guaranteed thread-safe way to access the dictionary. Your best bet is to either change your code so that you're not sharing the collection or to to lock the dictionary when accessing:

object dictLock = new object();

internal List<string> GetListOfEntities()
{            
    lock (dictLock)
    {
        return ModelFacade._totalListOfStkObjects.Keys.ToList();
    }
}

Make sure you also lock the dictionary when modifying it in another thread.

安静被遗忘 2024-10-18 17:09:20

如果您使用的是 .NET 4,请将 Dictionary 更改为 ConcurrentDictionary。这是一个简单的示例,可以模拟您的问题并解决它。

class DataItem
{
    public int Data { get; set; }
    public bool IsDirty { get; set; }
}

var data = new ConcurrentDictionary<string, DataItem>();
Thread addingItems = new Thread(() =>
    {
       for (int i = 0; i < 10000; i++)
       {
           data.TryAdd("data " + i, new DataItem { Data = i, IsDirty = true });
           Thread.Sleep(100);
       }
    });
Thread fetchingItems = new Thread(() =>
    {
        int count = 0;
        while (count < 100)
        {
            foreach (var item in data)
            {
                if (item.Value.IsDirty)
                {
                    Console.WriteLine(item.Key + " " + item.Value);
                    item.Value.IsDirty = false;
                    count++;
                }
            }
        }
    });
addingItems.Start();
fetchingItems.Start();

Change your Dictionary to ConcurrentDictionary if you are using .NET 4. Here is an easy example to simulate your question and resolve it.

class DataItem
{
    public int Data { get; set; }
    public bool IsDirty { get; set; }
}

var data = new ConcurrentDictionary<string, DataItem>();
Thread addingItems = new Thread(() =>
    {
       for (int i = 0; i < 10000; i++)
       {
           data.TryAdd("data " + i, new DataItem { Data = i, IsDirty = true });
           Thread.Sleep(100);
       }
    });
Thread fetchingItems = new Thread(() =>
    {
        int count = 0;
        while (count < 100)
        {
            foreach (var item in data)
            {
                if (item.Value.IsDirty)
                {
                    Console.WriteLine(item.Key + " " + item.Value);
                    item.Value.IsDirty = false;
                    count++;
                }
            }
        }
    });
addingItems.Start();
fetchingItems.Start();
明月松间行 2024-10-18 17:09:20

您可以将字典包装在线程安全的单例类中。这应该为 Dictionary 提供 ConcurrentDictionary 的所有功能。引用字典应该只需要一层额外的间接层。

参考:

Singleton.Instance.myDictionary.Add(1, "Hello World");

声明:

public sealed class Singleton
{
    private static volatile Singleton instance;
    private static object syncRoot = new Object();
    public Dictionary<int, string> myDictionary = new Dictionary<int, string>();

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }
}

此处了解有关 C# 中单例模式的更多信息。请注意,此链接上的模式与我的示例代码之间只有一处区别。

You can wrap the dictionary up in a thread-safe singleton class. This should provide all of the functionality of ConcurrentDictionary to Dictionary. Referencing the Dictionary should only require one additional layer of indirection.

Reference:

Singleton.Instance.myDictionary.Add(1, "Hello World");

Declaration:

public sealed class Singleton
{
    private static volatile Singleton instance;
    private static object syncRoot = new Object();
    public Dictionary<int, string> myDictionary = new Dictionary<int, string>();

    private Singleton() {}

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new Singleton();
                }
            }
            return instance;
        }
    }
}

Look here for more information on the Singleton Pattern in C#. Note that there is only one difference between the pattern on this link and my example code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文