gpt4 book ai didi

c# - 并发线程可以同时检查同一个对象锁吗?

转载 作者:行者123 更新时间:2023-11-30 22:12:34 25 4
gpt4 key购买 nike

如果我有这样的语句怎么会:

private int sharedValue = 0;

public void SomeMethodOne()
{
lock(this){sharedValue++;}
}

public void SomeMethodTwo()
{
lock(this){sharedValue--;}
}

所以一个线程要进入一个锁,它必须首先检查是否有另一个线程正在操作它。如果不是,它可以进入并必须向内存写入一些东西,这肯定不是原子的,因为它需要读写。

那么为什么一个线程读取锁而另一个线程将其所有权写入锁是不可能的呢?

为了简化为什么两个线程不能同时进入锁?

最佳答案

看起来你基本上是在问锁是如何工作的。在尚未构建锁的情况下,锁如何以原子方式维护内部状态?好像是 chicken and egg problem一开始不是吗?

神奇的一切都是因为 compare-and-swap 而发生的(CAS) 操作。 CAS 操作是一个硬件级指令,可以做两件重要的事情。

  • 它会生成内存屏障,从而限制指令重新排序。
  • 它将内存地址的内容与另一个值进行比较,如果它们相等,则将原始值替换为新值。它以原子方式执行所有这些操作。

在最基本的层面上,这就是技巧的实现方式。并不是所有其他线程在另一个线程正在写入时都被阻止读取。这是完全错误的思考方式。实际发生的是所有线程都同时充当编写器。该策略比悲观更乐观。每个线程都试图通过执行这种称为 CAS 的特殊写入来获取锁。实际上,您可以通过 Interlocked.CompareExchange (ICX) 方法访问 .NET 中的 CAS 操作。每个同步原语都可以从这个单一操作中构建。

如果我要完全用 C# 从头开始​​编写一个类似 Monitor 的类(这是 lock 关键字在幕后使用的),我可以使用Interlocked.CompareExchange 方法。这是一个过于简化的实现。请记住,这肯定不是 .NET Framework 是如何做到的。1我提供下面代码的原因是向您展示它如何可以 使用纯 C# 代码完成,不需要幕后的 CLR 魔术,因为它可能会让您思考 Microsoft 是如何实现它的。

public class SimpleMonitor
{
private int m_LockState = 0;

public void Enter()
{
int iterations = 0;
while (!TryEnter())
{
if (iterations < 10) Thread.SpinWait(4 << iterations);
else if (iterations % 20 == 0) Thread.Sleep(1);
else if (iterations % 5 == 0) Thread.Sleep(0);
else Thread.Yield();
iterations++;
}
}

public void Exit()
{
if (!TryExit())
{
throw new SynchronizationLockException();
}
}

public bool TryEnter()
{
return Interlocked.CompareExchange(ref m_LockState, 1, 0) == 0;
}

public bool TryExit()
{
return Interlocked.CompareExchange(ref m_LockState, 0, 1) == 1;
}
}

这个实现演示了一些重要的事情。

  • 它展示了如何使用 ICX 操作以原子方式读取和写入锁状态。
  • 它展示了等待是如何发生的。

请注意我是如何使用 Thread.SpinWaitThread.Sleep(0)Thread.Sleep(1)Thread .Yield 在等待获取锁时。等待策略过于简化,但它确实近似于 real life algorithm implemented in the BCL。已经。我故意在上面的 Enter 方法中保持代码简单,以便更容易发现关键位。这不是我通常执行此操作的方式,但我希望它确实能说明要点。

另请注意,我上面的 SimpleMonitor 有很多问题。这里只是一些。

  • 它不处理嵌套锁定。
  • 它不像真正的Monitor 类那样提供WaitPulse 方法。他们真的很难做对。

1CLR 实际上会使用存在于每个引用类型上的特殊内存块。该内存块称为“同步块(synchronized block)”。 Monitor 将操作此内存块中的位来获取和释放锁。此操作可能需要内核事件对象。您可以在 Joe Duffy's blog 上阅读更多相关信息.

关于c# - 并发线程可以同时检查同一个对象锁吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19624942/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com