如何使非线程安全的第三方库实际上是线程安全的?

时间:2014-06-19 12:40:13

标签: c# .net thread-safety

我有一个提供课程的第三方图书馆。他们的文件说:

  

线程安全

     

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

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

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

修改

有关第三方课程的更多信息。它是一个通信库,可以在此计算机或其他计算机上打开与另一个进程的通信链接。通信链路的另一端旨在接受并发连接。因此,我不需要使用lock来同步我的方法调用。但是,每个实例都不是线程安全的。

2 个答案:

答案 0 :(得分:3)

假设您不需要对象完全相互交互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));
        }
    }
}

另一种方法是编写一个线程安全的代理类,它为每个操作使用锁定 - 但如果你有多个你希望“原子地”执行的操作(即没有交错其他调用),那么仍会出现问题。

答案 1 :(得分:0)

我认为在这个类上面创建一个使用Monitors(lock关键字)或其他线程阻塞同步构造来阻止所有操作的包装器可以提供帮助。

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

在后处理过程中,您无法确保安全和不安全的安全。首先必须考虑这些品质,这甚至不是你的图书馆。