c# - 我可以在 C# 中覆盖已被 Locked() 的对象吗?

标签 c# .net multithreading

我有几个对象要发送到服务器,但我想确保这是将数据从 Stage 移动到 Upload 的唯一线程。以下代码在多线程环境中有效吗?

        List<CounterInternal> UploadToServer = new List<CounterInternal>();
        List<CounterInternal> StagingQueue = new List<CounterInternal>();
      lock (this.UploadToServer)
        lock (this.StagingQueue)
        {
            if (UploadToServer.Count == 0)
            {
                UploadToServer = StagingQueue.DoDeepCopyExtensionMethod();
                // is the following line valid given that I have a Lock() on it?
                StagingQueue = new List<CounterInternal>();
            }
        }
      }

最佳答案

从技术上讲,是的,但这是个坏主意。考虑这个 C# 源文件:

using System;

class Foo {
    static object foo = new object();
    static void Main() {
        lock (foo) {
            foo = new object();
        }

    }
}

Main() 方法将编译为:

.method private static  hidebysig
       default void Main ()  cil managed
{
    // Method begins at RVA 0x2100
    .entrypoint
    // Code size 35 (0x23)
    .maxstack 3
    .locals init (
            object  V_0)
    IL_0000:  ldsfld object Foo::foo
    IL_0005:  stloc.0
    IL_0006:  ldloc.0
    IL_0007:  call void class [mscorlib]System.Threading.Monitor::Enter(object)
    .try { // 0
      IL_000c:  newobj instance void object::'.ctor'()
      IL_0011:  stsfld object Foo::foo
      IL_0016:  leave IL_0022

    } // end .try 0
    finally  { // 0
      IL_001b:  ldloc.0
      IL_001c:  call void class [mscorlib]System.Threading.Monitor::Exit(object)
      IL_0021:  endfinally
    } // end handler 0
    IL_0022:  ret
} // end of method Foo::Main

这对应于以下来源(手工反编译):

static void Main() {
    object V_0 = foo;
    Monitor.Enter(V_0);
    try {
        foo = new object();
    } finally {
         Monitor.Exit(V_0);
    }
}

因此被锁定的对象将存储在一个本地——这保证了即使存储在字段中的对象引用被替换,对象的监视器也会被释放。单独使用此技术不会产生死锁,并且已经在 Monitor.Enter() 上阻塞的任何其他线程将像往常一样继续阻塞,直到该线程释放锁。

但是,任何在您重新分配对象之后但在事件线程释放锁之前进入此方法的线程都将获取对新对象的锁 对象,因此锁 block 中可以同时有两个线程。

更好的解决方案是使用一个单独的对象并锁定它。我通常使用 System.Object 类(或只是 object),因为它所做的只是充当互斥体。这将允许所有线程锁定同一个对象,同时允许更改其他对象引用。当您需要锁定以改变无法锁定的值类型时,这也是一种有用的技术。

关于c# - 我可以在 C# 中覆盖已被 Locked() 的对象吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4703835/

相关文章:

c# - linq 从子集合中选择项目

c# - .NET IBM DB2BulkCopy-确定是否由于错误导致插入失败

c# - C# 和 C++ 之间的编码,以及责任的杂耍

python - 调用 Flask app.run 后,我可以让 Python 代码继续执行吗?

java - 创建多线程 Java 服务器聊天应用程序。

C#,从二进制文件中读取结构

c# - EF 一对一主要关系错误

c# - 字符串替换在 asp.net 中不起作用

.net - 如何从 .NET 中的 CultureInfo 获取 ISO 3166 国家/地区代码

java - 让多个线程对数据集进行操作,而一个线程将其汇总