C# 线程安全与 get/set

2023-12-05

这是 C# 的详细问题。

假设我有一个带有对象的类,并且该对象受锁保护:

Object mLock = new Object();
MyObject property;
public MyObject MyProperty {
    get {
         return property;
    }
    set { 
         property = value; 
    }
}

我希望轮询线程能够查询该属性。我还希望线程偶尔更新该对象的属性,有时用户可以更新该属性,并且用户希望能够看到该属性。

下面的代码能正确锁定数据吗?

Object mLock = new Object();
MyObject property;
public MyObject MyProperty {
    get {
         lock (mLock){
             return property;
         }
    }
    set { 
         lock (mLock){
              property = value; 
         }
    }
}

我所说的“适当”是指,如果我想打电话

MyProperty.Field1 = 2;

或者其他什么,当我进行更新时该字段会被锁定吗?是由 equals 运算符在“get”函数范围内完成的设置,还是“get”函数(因此锁定)首先完成,然后设置,然后调用“set”,从而绕过锁?

编辑:既然这显然不起作用,那什么可以呢?我需要做类似的事情吗:

Object mLock = new Object();
MyObject property;
public MyObject MyProperty {
    get {
         MyObject tmp = null;
         lock (mLock){
             tmp = property.Clone();
         }
         return tmp;
    }
    set { 
         lock (mLock){
              property = value; 
         }
    }
}

这或多或少只是确保我只能访问副本,这意味着如果我让两个线程同时调用“get”,它们每个都会以相同的 Field1 值开始(对吗?)。有没有一种方法可以对有意义的属性进行读写锁定?或者我应该限制自己锁定函数部分而不是数据本身?

只是为了让这个示例有意义:MyObject 是一个异步返回状态的设备驱动程序。我通过串行端口向它发送命令,然后设备在自己的最佳时间内响应这些命令。现在,我有一个线程轮询其状态(“你还在吗?你能接受命令吗?”),一个等待串行端口响应的线程(“刚刚得到状态字符串 2,一切都很好”) ),然后是 UI 线程,它接受其他命令(“用户希望你做这件事。”)并发布来自驱动程序的响应(“我刚刚完成了这件事,现在用它更新 UI”)。这就是为什么我想锁定对象本身,而不是对象的字段;这将是大量的锁、a 和 b,并非此类的每个设备都具有相同的行为,只是一般行为,因此如果我对锁进行个性化,我必须编写大量单独的对话框。


不,您的代码不会锁定对从返回的对象的成员的访问MyProperty。它只锁MyProperty itself.

您的示例用法实际上是将两个操作合二为一,大致相当于:

// object is locked and then immediately released in the MyProperty getter
MyObject o = MyProperty;

// this assignment isn't covered by a lock
o.Field1 = 2;

// the MyProperty setter is never even called in this example

简而言之 - 如果两个线程访问MyProperty同时,getter 会短暂阻塞第二个线程,直到将对象返回给第一个线程,but然后它也会将该对象返回给第二个线程。然后,两个线程都将拥有对该对象的完整、未锁定的访问权限。

编辑以回应问题中的更多细节

我仍然不能 100% 确定您要实现的目标,但如果您只想对对象进行原子访问,那么您不能对对象本身进行调用代码锁定吗?

// quick and dirty example
// there's almost certainly a better/cleaner way to do this
lock (MyProperty)
{
    // other threads can't lock the object while you're in here
    MyProperty.Field1 = 2;
    // do more stuff if you like, the object is all yours
}
// now the object is up-for-grabs again

并不理想,但只要对对象的所有访问都包含在lock (MyProperty)那么这种方法将是线程安全的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# 线程安全与 get/set 的相关文章

随机推荐