功夫熊猫大侠 2024-06-14 16:31 采纳率: 100%
浏览 8
已结题

在C#中使用多线程和一集合交互,从集合中不断移除数据,如何确保数据的正确性

C#多线程数据同步

在C#中使用多线程和一集合交互,从集合中不断移除数据,如何确保数据的正确性?

  • 写回答

3条回答 默认 最新

  • 专家-赤兔[在线] 优质创作者: 编程框架技术领域 2024-06-14 16:31
    关注

    引自免费微信小程序:皆我百晓生

    在C#中,当多个线程尝试访问和修改同一个集合时,确实存在数据不一致的风险。为了确保数据的正确性和线程安全,可以采用几种不同的策略。下面将详细介绍这些策略,并提供示例代码。

    1. 使用线程安全的集合

    C# 提供了线程安全的集合类型,如 ConcurrentQueue<T>ConcurrentBag<T>。这些集合内部已经实现了锁机制,因此可以在多线程环境中安全地进行添加和移除操作。

    示例:使用 ConcurrentQueue<T>

    using System;
    using System.Collections.Concurrent;
    using System.Threading;
    
    class Program
    {
        static void Main()
        {
            var queue = new ConcurrentQueue<int>();
            for (int i = 0; i < 10; i++)
                queue.Enqueue(i);
    
            Thread thread1 = new Thread(() => RemoveItems(queue));
            Thread thread2 = new Thread(() => RemoveItems(queue));
    
            thread1.Start();
            thread2.Start();
    
            thread1.Join();
            thread2.Join();
        }
    
        static void RemoveItems(ConcurrentQueue<int> queue)
        {
            while (queue.TryDequeue(out int item))
            {
                Console.WriteLine($"Removed: {item}");
                Thread.Sleep(100); // 模拟处理时间
            }
        }
    }
    

    2. 使用锁(Mutex)

    锁是一种更通用的方法,可以应用于任何类型的集合。通过在访问集合前后加锁和解锁,可以确保在任何时候只有一个线程可以访问集合。

    示例:使用 lock 关键字

    using System;
    using System.Collections.Generic;
    using System.Threading;
    
    class Program
    {
        static List<int> list = new List<int>();
        static object locker = new object();
    
        static void Main()
        {
            for (int i = 0; i < 10; i++)
                list.Add(i);
    
            Thread thread1 = new Thread(RemoveItems);
            Thread thread2 = new Thread(RemoveItems);
    
            thread1.Start();
            thread2.Start();
    
            thread1.Join();
            thread2.Join();
        }
    
        static void RemoveItems()
        {
            lock (locker)
            {
                if (list.Count > 0)
                {
                    int item = list[0];
                    list.RemoveAt(0);
                    Console.WriteLine($"Removed: {item}");
                }
            }
            Thread.Sleep(100); // 模拟处理时间
        }
    }
    

    3. 使用 ReaderWriterLockSlim

    ReaderWriterLockSlim 是一种高级的锁机制,允许多个读取者同时访问资源,但写入者(即修改集合)必须独占资源。这可以提高性能,尤其是在读取操作远多于写入操作的情况下。

    示例:使用 ReaderWriterLockSlim

    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    
    class Program
    {
        static List<int> list = new List<int>();
        static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
    
        static void Main()
        {
            for (int i = 0; i < 10; i++)
                list.Add(i);
    
            Task.Run(() => RemoveItems());
            Task.Run(() => RemoveItems());
    
            Task.WaitAll();
        }
    
        static void RemoveItems()
        {
            rwLock.EnterWriteLock();
            try
            {
                if (list.Count > 0)
                {
                    int item = list[0];
                    list.RemoveAt(0);
                    Console.WriteLine($"Removed: {item}");
                }
            }
            finally
            {
                rwLock.ExitWriteLock();
            }
            Thread.Sleep(100); // 模拟处理时间
        }
    }
    

    以上三种方法都可以有效地保护集合免受多线程并发修改的影响,选择哪一种取决于具体的应用场景和性能需求。在大多数情况下,ConcurrentQueue<T>ConcurrentBag<T> 会是首选,因为它们提供了最佳的性能和易用性。如果需要更复杂的锁控制,那么 lockReaderWriterLockSlim 将是更好的选择。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 6月22日
  • 已采纳回答 6月14日
  • 创建了问题 6月14日