MSpec:如何使静态变量线程安全?

4

我正在使用MSpec进行我的最新项目,总体而言,我对它非常满意。然而,当我的测试在并行运行时,我遇到了一个关于并发的问题,想知道是否有人遇到过这个问题,或者更好的是,是否有解决方案?

MSpec在很大程度上依赖于静态方法和变量来工作。

现在看起来,当我在基类中定义静态变量,并且多个测试类使用它们,并且我并行运行我的测试时,它们共享相同的静态变量,从而干扰彼此。

我同时使用NCrunch和Resharper作为我的测试运行程序,我在两个程序中都遇到了这个问题。

有人熟悉这个问题吗?


这不是和 https://dev59.com/VXM_5IYBdhLWcg3wt1vD 一样吗? - PKeidel
可以请您发布一个简单的示例/重现吗?我希望将其包含在我们的示例中。谢谢! - Alexander Groß
2个回答

1
首先,我建议阅读 MSDN 上的线程安全指南。这将为您提供在 C# 中使方法线程安全的方法和原因的概述。
以下规则概述了实现线程的设计指南:
- 避免提供更改静态状态的静态方法。在常见的服务器场景中,静态状态是跨请求共享的,这意味着多个线程可以同时执行该代码。这会导致线程错误的可能性。考虑使用一种将数据封装到不跨请求共享的实例中的设计模式。 - …添加锁以创建线程安全代码会降低性能,增加锁争用,并创建死锁错误的可能性。 - 注意锁定部分中的方法调用。当类A中的静态方法调用类B中的静态方法,反之亦然时,可能会导致死锁。如果A和B都同步其静态方法,则会导致死锁。您可能只会在重度线程压力下发现此死锁。 - 注意锁语句(Visual Basic中的SyncLock)的问题。使用锁语句解决所有线程问题很诱人。但是,System.Threading.Interlocked类对于必须是原子的更新更为优越...
作为一般性的注意事项,我喜欢使用一种方法(如果可能的话)来使一个方法(静态或非静态)不可变。为了做到这一点,所有变量都应该是本地的(在堆栈上创建本地变量或作为参数传递给方法)。通过确保只使用本地变量或成员变量是不可变的,每个线程将在自己的隔间中运行,变量的更改不会影响另一个线程。这是我在.NET模拟软件中广泛使用的方法,以允许C#高性能多线程无锁操作。
或者,如果变量必须是成员变量且可变,则可以通过锁定关键字来保护对它们的访问。在使用锁时要小心,因为它会导致上下文切换(减慢速度),并引入死锁情况的可能性。它也不能保证线程安全,因为使用锁必须防止特定场景的发生。
如需进一步阅读,建议查看以下相关问题,其中描述了C#中的线程安全和不可变性:

此致敬礼,


0

默认情况下,静态字段不是线程安全的。如果要使它们线程安全,可以使用[ThreadStatic]属性进行装饰。

请查看MSDN上的ThreadStaticAttribute 类了解更多信息。


3
ThreadStatic 为每个线程创建一个单独的静态字段,严格来说不同于线程安全性,它确保每个调用者可以安全地调用静态字段。我建议使用静态属性,在获取和设置方法中确保线程安全。 - hcb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接