C# version of java's synchronized keyword?
C++有自己的Java"同步"关键字吗?
即在Java中,它可以被指定给函数、对象或代码块,如:
1 2 3
| public synchronized void doImportantStuff() {
// dangerous code goes here.
} |
或
1 2 3 4 5 6 7
| public void doImportantStuff() {
// trivial stuff
synchronized(someLock) {
// dangerous code goes here.
}
} |
- 块窗体需要引用来锁定。在方法形式中,lock对象是隐式的(对于静态方法,也可以是类[this.class,而不是getClass()],但不要锁定类)。
- 仍然不受保护?我总是来这里,因为我记不起那条[MethodImpl(MethodImplOptions.Synchronized)]线。
- 我认为你的第二个代码片段不会编译-它需要在某些东西上进行同步。
第一-大多数类永远不需要是线程安全的。使用yagni:只有当你知道你将要使用它(并测试它)时才应用线程安全。
对于方法级的东西,有[MethodImpl]:
1 2
| [MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */} |
这也可用于访问器(属性和事件):
1 2 3 4 5 6 7 8
| private int i;
public int SomeProperty
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return i; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { i = value; }
} |
注意,默认情况下类似字段的事件是同步的,而自动实现的属性不是:
1 2
| public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized |
我个人不喜欢执行MethodImpl,因为它锁定了this或typeof(Foo),这违背了最佳实践。首选选项是使用您自己的锁:
1 2 3 4
| private readonly object syncLock = new object();
public void SomeMethod () {
lock(syncLock ) { /* code */ }
} |
请注意,对于类似字段的事件,锁定实现依赖于编译器;在旧的Microsoft编译器中,锁定实现是一个lock(this)/lock(Type)-但是,在较新的编译器中,锁定实现使用Interlocked-这样线程安全,不存在不好的部分。
这允许更精细的使用,并允许使用Monitor.Wait/Monitor.Pulse等在线程之间进行通信。
相关的博客条目(稍后重新访问)。
- @你的问题是什么?那句话是真的。绝大多数类对线程安全没有要求,不会对线程安全进行测试,并且具有线程安全性会影响性能。真正需要担心线程的类型数量非常少——有意同步的集合、多路复用器等。
- 抱歉@marc,我在不久后删除了评论(没有解释,它没有任何作用,只是闻起来像个怪人)。我在这里重复一遍:"大多数类永远不需要线程安全"嗯?我"嗯"的原因是什么?这是一个非常笼统的说法吗?我仍然不同意,但也许这正是你所说的方式——在我看来,你应该始终知道你的类将在(框架等)中使用的上下文。很同意这个数字很小,但这里很关键。diff设计可以完全移除锁;不可变类,并通过同步集合等保护共享状态。
- @我确实非常熟悉深度线程代码…但这是个例外,而不是规范——即便如此,并非所有涉及的课程都需要参与进来。
- 我想我应该简单地说:"大多数类永远不需要线程安全",但是"所有开发人员都必须知道并发性"。回想起来,我同意这个数字是非常小的(而且绝对是你想在一个地方得到正确的东西,允许大多数类在不注意其多线程环境的情况下进行交互)。希望我能更快地删除评论=)
- Marc的链接博客帖子有2010年3月的后续报道称,在.NET 4.0中,MethodImpl和类似于字段的事件现在生成了良好的同步代码,不再需要使用自己的锁。
- @罗约凯恩,我会编辑的
- 如今,大多数应用程序都是基于Web的,通过依赖注入与依赖重实例重用和复杂对象生命周期的框架一起提供服务。这些天默认的心态往往偏向线程安全方面。
- 请注意,msdn建议不要使用MethodImplOptions。Synchronized:对于公共类型,不建议像使用Synchronized标志那样锁定实例或类型,因为您自己之外的代码可以锁定公共类型和实例。这可能会导致死锁或其他同步问题。
- @MarcGravell考虑重新安排您的答案,以突出最佳实践,并可能添加属性样本(请参阅stackoverflow.com/questions/33684965/…例如与建议混淆)。
- @Alexeilevenkov同步是如此的上下文化,以至于很难给出一个通用的"最佳实践"…
- @MarcGravell我不会把一个最不可能被正确使用的人放在第一位,但那是你的要求。(评论很快就会自我毁灭)。
- 另一个详细的C实现。
- 我得到了'MethodImplOptions' does not contain a definition for 'Synchronized'。
- @Elazar你有没有可能瞄准一个异国情调的框架?统一、单一、网络标准等?它确实存在于.NET:msdn.microsoft.com/en-us/library/…
- 你是对的,我已经安装了一些最低版本的vs.但是我如何知道要添加哪些组件?
- @伊拉扎尔,无论你用的是什么版本的vs。重要的是你的目标是什么框架。
- @MarcGravell很好,目标框架是.NETCoreApp 1.1,但我没有其他选择。
- 我无法彻底改变目标框架,所以我不得不创建一个新项目——现在是.NET Framework,而不是.NETCore。
- @Elazar现在太晚了,但是要记录下来:如果您使用.NET标准/.NET核心模板创建了框架,那么对csproj来说,更改框架只是一行更改,而且常规的.NET和多目标的.NET都是可用的。然而,围绕这一点的IDE工具是非常糟糕的-您只需要知道您可以更改什么和更改什么:)
- 谢谢。我尝试了一些在另一个答案中发现的一行更改,它使项目无法读取(可能与nuget有关),因此我认为这是错误的一行:)
1 2 3 4 5 6
| static object Lock = new object();
lock (Lock)
{
// do stuff
} |
- 确实要将锁对象声明为静态的..
- 当然,所以每个线程都可以很容易地访问它而不需要传递引用。
- 如果我们是在询问者问题的上下文中,那么我们将讨论实例方法。使用static意味着如果线程1调用instance1.dosomething(),而线程2调用instance2.dosomething,则第二个调用将阻塞,即使它是完全不同的对象。线程2的调用不应阻塞,除非有人在同一对象上调用dosometing。不是说你错了,而是说理解在这里使用static的效果是很重要的,因为它可能通过全局阻塞而不是基于每个实例阻塞而导致性能不佳。
- @aaronls静态锁,如果在比对象本身更大的作用域上执行操作时非常有用。例如,Web服务总是会发生。
- @詹格斯曼感谢你的回答,这正是我在寻找那个问题时所寻求的。
- -1因为这与OP要求的行为不同。这是类锁,而不是实例锁。
- 使用static:假设有一些奇怪的线程您从未考虑过为了其他锁定目的访问这个staticLock对象-意味着不在这个代码块上。然后,通过这个奇数线程获取Lock。现在线程池出现了,它们将访问您的代码块,但其中的非线程无法进入,因为奇数线程尚未释放Lock对象。我认为这是一个非常特殊的情况,你想通过了解影响来配合。如果使用实例方法,则不要将static锁用作常见的实践。我来自Java,但概念应该是一样的:我想:
Does c# have its own version of the java"synchronized" keyword?
不需要。在C中,您显式地使用希望跨异步线程同步处理的cx1(0)资源。lock打开一个块;它不在方法级别上工作。
但是,底层机制是类似的,因为lock通过在运行时调用Monitor.Enter(随后调用Monitor.Exit)工作。根据Sun文档,Java的工作方式是一样的。
- 它没有等价的"关键字",但正如上面MarcGravell的答案所示,您可以使用[MethodImpl(MethodImplOptions.Synchronized)]注释在方法级别进行同步。
- 由于Java的EDCOX1对0的方法基本上是EDOCX1,1,那么C上的相似性不是EDCOX1×2吗?
- 仅部分正确的SRiHARSHILKAKAPATI,一个方法上的Java EDCOX1×0 }关键字更像:EDCOX1×4,只有在静态方法中它的行为像EDCX1×5。
请注意,使用完整的路径,行:[MethodImpl(MethodImplOptions.Synchronized)]应该看起来像
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
- 或者你可以直接用using System.Runtime.CompilerServices;。
- 我写这篇评论的时候,我还不知道如何自动插入使用语句,在编程C_不超过几天或几周后,我对这3个赞成票感到惊讶。
- 你至少帮助了3个开发人员,这很好:)
您可以使用lock语句来代替。我想这只能代替第二种版本。另外,请记住,synchronized和lock都需要在对象上操作。