C# 空锁块会消失 "optimized" 吗?

C# Does an empty lock block get "optimized" away?

我找不到有关 C# 编译器或 JIT 是否会删除内部没有代码的锁定语句的任何信息。这会始终生成并执行 Monitor.EnterMonitor.Exit 调用吗?

lock(lockObj) { }

我正在尝试做的事情的(大大简化的)版本(是的,我知道在锁中调用回调是不好的):

public class ExecutionSource
{
    private List<Action<object>> _callbacks = new List<Action<object>>();
    private object _value;

    public void AddListener(Action<object> listener)
    {
        object temp = _value;
        if (temp != null)
        {
            listener(temp);
            return;
        }
        lock (_callbacks)
        {
            temp = _value;
            if (temp != null)
            {
                listener(temp);
            }
            else
            {
                _callbacks.Add(listener);
            }
        }
    }

    public void Execute(object value)
    {
        if (value == null) throw new InvalidOperationException("value must be non-null");
        if (Interlocked.CompareExchange(ref _value, value, null) != null)
        {
            throw new InvalidOperationException("Can only execute once.");
        }
        lock (_callbacks) { } // Wait for a listener that is currently being added on another thread. No need to lock the entire loop.
        foreach (var callback in _callbacks)
        {
            callback(value);
        }
        _callbacks.Clear();
    }
}

不,他们没有。 CLI 不能假定没有其他线程已经锁定该对象。

如果任何其他线程(或您当前的代码)试图锁定,对象头或同步块 table 仍将标记有线程 ID 和 Monitor.Enter/Exit 上的非零递归计数在具有非零线程 ID 的对象上,它将进入自旋等待或在需要时提升为基于内核的事件。

就其价值而言,由于您不关心重新排序,并且根据您的用例,可能还有其他 synchronization primitives 可能更适合您的特定用例。比如重置事件等

根据 sharplib 我们可以看到编译器没有删除空锁块。而且,我无法想象我们如何在真正的多线程环境中在编译时优化它并确保我们不会破坏任何东西。