【问题标题】:In ConcurrentDictionary, is the read operation reading the latest updated value?在 ConcurrentDictionary 中,读取操作是否读取最新更新的值?
【发布时间】:2016-02-21 22:43:13
【问题描述】:

我在我的代码中使用了ConcurrentDictionary (ongoingConnectionDic):

  1. 我检查字典中是否存在串行端口号。
  2. 如果不存在,我将其添加到字典中。
  3. 我使用串口进行通信。
  4. 我从ongoingConnectionDic 中删除了该元素。
  5. 如果存在,我将线程置于等待状态。

我的问题是,我能否确保在执行读取操作时,没有其他线程同时写入/更新值?那么,我是否正在阅读字典的最新值?

如果没有,我如何实现我想要的?

示例程序:

    class Program
{
    // Dictionary in question
    private static ConcurrentDictionary<string, string> ongoingPrinterJobs = 
        new ConcurrentDictionary<string, string>();

    private static void sendPrint(string printerName)
    {
        if (ongoingPrinterJobs.ContainsKey(printerName))
        {
            // Add to pending list and run a thread to finish pending jobs by calling print();


        }
        else
        {
            ongoingPrinterJobs.TryAdd(printerName, ""); // -- Add it to the dictionary so that no other thread can
                                                        // use the printer

            ThreadPool.QueueUserWorkItem(new WaitCallback(print), printerName);
        }

    }

    private static void print(object stateInfo)
    {
        string printerName = (stateInfo as string);
        string dummy;
        // do printing work

        // Remove from dictionary
        ongoingPrinterJobs.TryRemove(printerName, out dummy);
    }


    static void Main(string[] args)
    {

        // Run threads here in random to print something on different printers
        // Sample run with 10 printers
        Random r = new Random();
        for ( int i = 0 ; i < 10 ; i++ )
        {
            sendPrint(r.Next(0, 10).ToString());
        }



    }

【问题讨论】:

  • 那么你需要在你自己实现IDictionary&lt;K, V&gt;的每个方法上使用课程lock
  • 即使这样做,尽管您只是将问题推到字典之外。您只是无法知道另一个线程正在锁后面等待更新值。因此,最新的值可能已经计算出来,但没有在字典中更新。
  • 能否请您发布您的代码,而不是您在问题中发布的模糊的五个步骤?
  • 我已经添加了上面的代码。请建议。谢谢。
  • 你会得到最后写的。如果一个线程在一纳秒后更新字典条目,那么你读到的不再是最后一个。 ConcurrentDictionary 是线程安全的,它不会自动使用线程安全的方式。

标签: c# concurrentdictionary


【解决方案1】:

并发集合在枚举时获取集合的“快照”。这是为了防止枚举器在另一个线程出现并写入集合时变得无效。

ContainsKey 之类的方法可能会枚举字典中的项目(您必须查看实现),在这种情况下,您可能正在读取陈旧的数据。

所有并发集合允许您做的是确保您可以枚举集合,即使在您枚举时另一个线程写入它。标准集合不是这种情况。

话虽如此,正如其他人在他们的 cmets 中提到的那样,仍然必须考虑其他线程安全问题(例如竞争条件)。

在您尝试读取值之后但在写入 ia 值之前防止有人将值插入集合的唯一方法是在读取值开始之前lock 集合,以确保同步访问整个事务中的集合(即值的读取和后续写入)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-09
    • 2014-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 2019-10-30
    • 1970-01-01
    相关资源
    最近更新 更多