【问题标题】:How to make a non-thread-safe 3rd party library actually thread-safe?如何使非线程安全的 3rd 方库实际上是线程安全的?
【发布时间】:2014-08-10 00:11:46
【问题描述】:

我有一个提供课程的第 3 方库。他们的文件说:

线程安全

这种类型的公共静态(在 Visual Basic 中为共享)成员对于多线程操作是安全的。不保证实例成员是线程安全的。

我做了一些测试,我创建了 100 个线程。如果我将同一个对象传递给所有 100 个线程,确实存在线程安全问题,但如果每个线程创建自己的类实例,这些问题似乎就会消失。

我在这里使用 .NET 4.0。在我的应用程序中,有多个线程想要使用这个类,但我不想创建和销毁不必要的对象(它们应该在应用程序的生命周期内存在),所以我希望每个线程一个。这是对ThreadLocal<T> 类的适当使用吗?如果不是,处理这个问题的标准方法是什么?

编辑

有关第 3 方课程的更多信息。它是一个通信库,并打开到另一个进程的通信链接,无论是在这台计算机上还是在另一台计算机上。通信链路的另一端被设计为接受并发连接。因此,我不需要使用locks 来同步我端的方法调用。但是,每个实例都不是线程安全的。

【问题讨论】:

    标签: c# .net thread-safety


    【解决方案1】:

    假设您完全不需要对象之间的交互ThreadLocal<T> 是一个很好的选择。如果在一个线程中进行的修改意味着要在另一个线程中看到,这显然是行不通的,只是安全。

    是的,它会为每个线程创建一个对象 - 但除非创建对象真的很昂贵,否则您可能会拥有数百个实例,在大多数情况下这绝对没问题.

    一个典型的例子是System.Random

    • 您不希望临时创建实例,因为如果您不小心,最终会使用相同的种子创建多个实例
    • 这绝对是不是线程安全的。

    所以你可以这样做:

    public static class RandomProvider
    {
        private static readonly Random seedProvider = new Random();
    
        private static readonly ThreadLocal<Random> threadLocal =
            new ThreadLocal<Random>(InitializeNewRandom);
    
        public static Random GetRandomForThread()
        {
            return threadLocal.Value;
        }
    
        private static Random InitializeNewRandom()
        {
            lock(seedProvider)
            {
                return new Random(seedProvider.Next(int.MaxValue));
            }
        }
    }
    

    另一种方法是编写一个线程安全的代理类,该类对每个操作都使用锁定 - 但如果您有多个希望“原子”执行的操作(即不交错其他调用),这仍然存在问题。

    【讨论】:

    • 该类是一个通信客户端,连接到PC或另一台PC上的不同进程。另一端可以处理并发连接。我的应用程序中的各个实例应该进行交互(至少不在我的应用程序中)。
    • @ScottWhitlock:对。在这种情况下,它确实听起来很合适。为了测试,您可能需要引入中介(例如ClientProvider),请注意...
    • 是的,它已经在一个包装类中,我正在这样做,创建一个ClientProvider,它的唯一工作是返回客户端类的一个实例。该提供商将使用ThreadLocal&lt;T&gt;。谢谢!
    【解决方案2】:

    我认为在此类之上制作一个包装器,它可以使用 Monitors(lock 关键字)或其他线程阻塞同步结构来阻塞所有操作,这会有所帮助。

    但它不能保证不存在可能的死锁和竞争条件。如果不完全重写原始类及其使用者,您可能仍然会遇到问题。

    您不能在后处理中使不安全的事物安全,而使不安全的事物安全。必须首先考虑这些品质,这甚至不是您的图书馆。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      相关资源
      最近更新 更多