静态函数需要锁定机制吗?

11
我创建了一个名为 CommonUtils.cs 的文件,其中包含5个静态函数(这样我就可以在 Visual Studio 中为其他项目“复制”此 .cs 文件,因为我开发不同的 C# 应用程序),还有许多源文件。
现在,我已经将我的项目编译为 DLL。这个 dll 作为应用程序通过 IIS 服务器进行托管。许多客户使用这个 dll 来执行某些操作,比如生成报告。
我被告知,在这种情况下,“静态函数”不应该被大量使用,并且应该应用“锁定”机制,因为如果没有锁定,单个程序实例的多个线程或多个程序实例都可能表现出意外行为。这是真的吗?

4
你是否访问任何全局状态或仅使用参数?如果是后者,你就不需要锁定。 - Sriram Sakthivel
2
@AmirPopovich 那个链接中哪里说是真的?静态与线程安全无关。 - Sriram Sakthivel
4个回答

11
我被告知在这种情况下不能慷慨地使用"静态函数",应该应用"锁定"机制,因为没有锁定,单个程序实例的多个线程或多个程序实例都可能表现出意外行为。这是真的吗?
让我们一步一步来。什么是静态类?
静态类基本上与非静态类相同,但有一个区别:静态类不能被实例化。换句话说,您不能使用new关键字创建类类型的变量。因为没有实例变量,您通过使用类名本身访问静态类的成员。
CLR如何处理静态类?
与所有类类型一样,当引用类的程序加载时,.NET Framework公共语言运行时(CLR)加载静态类的类型信息。程序无法指定类何时加载。但是,在程序首次引用类之前,保证将其加载并初始化其字段,并调用其静态构造函数。静态构造函数只会调用一次,在应用程序域中,静态类会一直驻留在内存中。
现在为什么我们可能需要锁定?
基本上,在存在竞争条件时需要锁定。当某人可以在同一时间读取其他人可能更改它们的数据时。两个独立的线程可以访问共享资源,并且没有任何机制可以防止这种情况。为了回答您的问题,您首先必须回答另一个问题。
您的静态方法是否访问共享资源,并且可能存在竞争条件?如果是这样,那么您需要使用锁定。否则,不需要。

如果您需要了解静态类的更多信息,请查看此处。 而如果您需要更多关于线程同步技术的信息,请查看此处


是的。静态方法访问一个共同的资源(在我的情况下,一个文件,其中5个函数之一是getFileReadtillEnd(string))......因此,这需要“线程同步”,即我需要实现一个“锁定”机制。感谢大家的努力。我非常感激这个。 - Prasath Govind
2
@PrasathGovind 那么在读取文件内容时,您肯定需要使用锁语句。 - Christos

9

函数是不可变的,因此在调用函数时无需进行同步。函数参数是可变的,但每次调用都有自己的本地副本,因此也无需同步。

当多个线程在处理相同数据并且至少有一个写入器时,需要进行同步。这涉及到任何在线程之间共享的变量。对于静态变量和由静态变量可达的任何实例变量,需要特别注意。


5
函数参数可以被改变,但每次调用会创建一个本地副本。我认为这种说法有点误导。是的,每个函数都有引用类型的引用副本,但每个副本都指向相同的数据。 - Kenneth K.
4
@KennethK. 这与函数参数无关,这个规则始终适用。持有引用的变量与其指向的对象是独立的。了解引用和对象之间的区别是基本预期的知识。 - usr

0

看起来你有一个类库。以下是微软支持多线程的类库的指南:

  • 尽可能避免需要同步。这对于经常使用的代码尤其如此。例如,可以调整算法以容忍竞争条件而不是消除它。不必要的同步会降低性能并创建死锁和竞争条件的可能性。

  • 默认情况下使静态数据(Visual Basic中的Shared)线程安全。

  • 不要默认情况下使实例数据线程安全。添加锁以创建线程安全代码会降低性能,增加锁争用,并创建死锁的可能性。在常见的应用程序模型中,只有一个线程同时执行用户代码,这最小化了对线程安全的需求。因此,.NET Framework类库默认情况下不是线程安全的。

  • 避免提供更改静态状态的静态方法。在常见的服务器场景中,静态状态在请求之间共享,这意味着多个线程可以同时执行该代码。这打开了线程错误的可能性。考虑使用一种将数据封装到不跨请求共享的实例中的设计模式。此外,如果同步了静态数据,则在更改状态的静态方法之间的调用可能会导致死锁或冗余同步,从而对性能产生不利影响。

https://msdn.microsoft.com/zh-cn/library/1c9txz50(v=vs.110).aspx复制


-1

关于 "LOCK" 的解释,MSDN 上说:
lock 关键词通过获取给定对象的互斥锁、执行语句,然后释放锁,将语句块标记为临界区。

lock 关键字确保一个线程不会在另一个线程进入临界区的同时进入代码的临界区。如果另一个线程尝试进入锁定的代码,则会等待,阻塞,直到该对象被释放。

参考资料:
https://msdn.microsoft.com/zh-cn/library/c5kehkcz.aspx

在多线程中使用 LOCK 比每次创建静态函数更好。


4
为什么要这样做?基于什么原因?"相比每次创建静态函数,使用锁在多线程中更好。" 基于什么? - Kenneth K.
1
我的意思是,无论您使用静态函数还是非静态函数,都建议为线程的关键部分使用锁定。锁定将确保该部分仅可以被一个线程在任何时刻访问。 - Biswabid

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