【发布时间】:2010-11-25 17:16:47
【问题描述】:
有人能解释一下为什么线程的例子总是让一个对象(特别是一个成员变量)被多个线程访问吗?
我的问题是,将成员变量设为静态意味着它将在类的所有其他实例之间共享。有时我发现我希望一个类中的多个线程“接触”成员变量,但同时允许每个对象拥有自己的副本。
执行我提到的操作的答案是否只是替换:
- 使用 volatile 关键字
- 使用锁(对象)
【问题讨论】:
标签: c# multithreading synchronization
有人能解释一下为什么线程的例子总是让一个对象(特别是一个成员变量)被多个线程访问吗?
我的问题是,将成员变量设为静态意味着它将在类的所有其他实例之间共享。有时我发现我希望一个类中的多个线程“接触”成员变量,但同时允许每个对象拥有自己的副本。
执行我提到的操作的答案是否只是替换:
【问题讨论】:
标签: c# multithreading synchronization
没有什么要求成员变量是静态的线程。
大多数示例都使用静态变量,特别是因为它们试图展示如何在两个单独的线程之间同步数据。如果你想这样做,你需要有一个两个线程都可以访问的值。静态变量是最简单的选择,因为它们在任何地方都可以访问。
您可以轻松地将一个类的引用传递到您的线程中,并让该线程和您的主线程共享一个非静态成员变量。但是,您需要提供良好的锁定/同步机制,因为您将有两个线程共享一个类的一个实例。
【讨论】:
lock(object) 来访问多个线程共享的变量。这将为您提供独占访问权限,它会为您完成所有工作,因此所有线程始终获取最新值(内存屏障)。
如果您希望每个线程使用相同的成员变量,但还维护一个单独的副本,那么这里就有矛盾了。他们要么使用相同的变量,要么不使用。除非我没有正确理解你。
话虽如此,如果您确实需要多个线程访问一个静态字段,每个线程都维护自己的私有值,您可以使用ThreadStatic 属性。此属性确保静态字段对每个线程都是私有的(通常称为“线程本地”)。
[ThreadStatic]
private static bool s_threadHasDoneItsWork;
请注意,您不能通过静态构造函数或直接将线程本地静态字段初始化为static type field = value。 (编译器不会抱怨,但它不会正常工作。)
volatile 告诉运行时该字段(无论是否静态)必须始终直接从您的主内存访问,因此您不需要使用锁或内存屏障来同步线程和内核。可以这么说,它始终是最新的,而其他字段仍然可以等待您的处理器的内存缓存与您的主内存同步。
但这正是它所做的限制:仅访问该特定字段。一旦你读过它,这个值又是陈旧的,所以永远不要考虑做类似 volatileField++ 的事情(这意味着“读取 volatileField,在你刚刚读取的值上加一个,设置 volatileField”,而不是“增加 volatileField”,您需要为此使用 Interlocked 类,这要贵得多)。
使用 volatile 字段的一种安全方法是直接读取它们,但是当您修改它们时,请在读取或写入它们之前使用锁定机制。 (我能想到的唯一合理的例外是一个布尔标志,比如“我现在完成了”。)
毫无疑问,volatile 字段的实际用途相当有限。坚持简单的锁定; lock 关键字和对应的Monitor 类的方法负责单用户和内存同步(一旦你进入和退出锁)。
【讨论】: