【问题标题】:C# version of java's synchronized keyword?java的同步关键字的C#版本?
【发布时间】:2015-12-30 02:16:38
【问题描述】:

c# 是否有自己的 java“同步”关键字版本?

即在 java 中,它可以指定为函数、对象或代码块,如下所示:

public synchronized void doImportantStuff() {
   // dangerous code goes here.
}

public void doImportantStuff() {
   // trivial stuff

   synchronized(someLock) {
      // dangerous code goes here.
   }
}

【问题讨论】:

  • 块形式需要引用锁。在方法形式中,锁定对象是隐含的 this(或者静态方法的 Class [this.class,not getClass()],但不要锁定 Classes)。
  • 仍然不受保护?我总是来这里,因为我不记得那条[MethodImpl(MethodImplOptions.Synchronized)] 行了。
  • 我认为你的第二个 sn-p 不会编译 - 它需要在某些东西上同步

标签: c# java multithreading synchronization


【解决方案1】:

首先 - 大多数类永远不需要是线程安全的。使用YAGNI:仅在您知道自己将要使用它(并对其进行测试)时才应用线程安全。

对于方法级别的东西,有[MethodImpl]

[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}

这也可以用于访问器(属性和事件):

private int i;
public int SomeProperty
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    get { return i; }
    [MethodImpl(MethodImplOptions.Synchronized)]
    set { i = value; }
}

请注意,类字段事件默认同步的,而自动实现的属性不是

public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized

就我个人而言,我不喜欢MethodImpl 的实现,因为它会锁定thistypeof(Foo)——这违反了最佳实践。首选选项是使用您自己的锁:

private readonly object syncLock = new object();
public void SomeMethod() {
    lock(syncLock) { /* code */ }
}

请注意,对于类似字段的事件,锁定实现取决于编译器;在较旧的 Microsoft 编译器中,它是 lock(this) / lock(Type) - 但是,in more recent compilers it uses Interlocked 更新 - 因此线程安全,没有讨厌的部分。

这允许更细粒度的使用,并允许使用Monitor.Wait/Monitor.Pulse 等在线程之间进行通信。

一个相关的blog entry(后来的revisited)。

【讨论】:

  • @earcam 你的问题是?那句话是真的。绝大多数类不需要线程安全,不会测试线程安全,拥有线程安全会影响性能。真正需要担心线程的类型数量非常少 - 有意同步的集合、多路复用器等。
  • 我想我应该简单地说; “大多数类永远不需要是线程安全的”,但“所有开发人员都必须意识到并发性”。回想起来,我同意这个数字非常小(绝对是你想在一个地方做一次正确的事情,允许大多数类在不考虑它们的多线程环境的情况下进行交互)。希望我能更快地删除评论=)
  • Marc 的linked blog post 有一个March 2010 follow-up 说在.NET 4.0 中,MethodImpl 和类似字段的事件现在可以生成良好的同步代码,并且不再需要使用自己的锁。
  • 当今绝大多数应用程序都是基于 Web 的,由依赖于大量实例重用和通过依赖注入的复杂对象生命周期的框架提供服务。这些天的默认思维方式往往偏向于线程安全。
  • @Elazar 现在为时已晚,但记录在案:如果您使用 .net 标准/.net 核心模板创建框架,则更改框架是对他们 csproj 的单行更改 - 和常规.net 可用,多目标也可用。然而,围绕这一点的 IDE 工具简直太糟糕了——你只需要知道你可以改变什么以及改变什么:)
【解决方案2】:
static object Lock = new object();

lock (Lock) 
{
// do stuff
}

【讨论】:

  • 您确定要将您的锁对象声明为静态..?
  • 当然,所以每个线程都可以轻松访问它而无需传递引用。
  • 如果我们在提问者问题的上下文中,那么我们正在谈论实例方法。使用静态意味着如果线程 1 调用 instance1.DoSomething() 并且线程 2 调用 instance2.DoSomething,则第二个调用将阻塞,即使它是一个完全不同的对象。 thread2 的调用不应阻塞,除非有人在 同一个对象上调用 DoSomething。不是说你错了,而是说在这里理解使用 static 的效果很重要,因为它可能会因为全局阻塞而不是基于每个实例而导致性能下降。
  • @AaronLS 当你的对象在比它自己更大的范围内执行操作时,静态锁非常有用。例如,总是发生在网络服务中。
  • -1 因为这与 OP 要求的行为不同。这是类锁,不是实例锁。
【解决方案3】:

c# 是否有自己的 java“同步”关键字版本?

没有。在 C# 中,您显式地 lock 想要跨异步线程同步处理的资源。 lock 打开一个区块;它不适用于方法级别。

但是,底层机制是相似的,因为 lock 通过在运行时调用 Monitor.Enter(随后是 Monitor.Exit)来工作。根据Sun documentation,Java 的工作方式相同。

【讨论】:

  • 它没有等效的“关键字”,但正如 Marc Gravell 上面的回答所示,您可以使用 [MethodImpl(MethodImplOptions.Synchronized)] 注释在方法级别进行同步。
  • 既然 Java 的 synchronized on 方法基本上是 synchronized (this.getClass()) 在 C# 上不会是 lock(typeof(this)) 吗?
  • @SriHarshaChilakapati 这只是部分正确,java 的 synchronized 方法上的关键字更像:synchronized(this) ,只有在静态方法上它的行为类似于 synchronized(class)
【解决方案4】:

注意,带有完整路径的行:[MethodImpl(MethodImplOptions.Synchronized)] 应该看起来像

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]

【讨论】:

  • 或者你可以使用using System.Runtime.CompilerServices;
  • 在编写 C# 几天或几周后,我还不知道自动插入 using 语句,我写了这条评论,我对这 3 次投票感到惊讶。
  • 你帮助了至少 3 个开发者,这很好:)
【解决方案5】:

您可以改用lock 语句。我认为这只能替代第二个版本。另外,请记住synchronizedlock 都需要对对象进行操作。

【讨论】:

    猜你喜欢
    • 2022-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-12-09
    • 2012-03-01
    • 2021-10-26
    • 2011-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多