带有 get/set 的 C# 线程安全 [英] C# thread safety with get/set

查看:36
本文介绍了带有 get/set 的 C# 线程安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个 C# 的详细问题.

This is a detail question for C#.

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

Suppose I've got a class with an object, and that object is protected by a lock:

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

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

I want a polling thread to be able to query that property. I also want the thread to update properties of that object occasionally, and sometimes the user can update that property, and the user wants to be able to see that property.

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

Will the following code properly lock the data?

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

所谓正确",我的意思是,如果我想打电话

By 'properly', what I mean is, if I want to call

MyProperty.Field1 = 2;

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

or whatever, will the field be locked while I do the update? Is the setting that's done by the equals operator inside the scope of the 'get' function, or will the 'get' function (and hence the lock) finish first, and then the setting, and then 'set' gets called, thus bypassing the lock?

既然这显然不会奏效,那怎么办?我是否需要执行以下操作:

Since this apparently won't do the trick, what will? Do I need to do something like:

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 值开始(对?).有没有办法对有意义的属性进行读写锁定?或者我应该限制自己锁定函数部分而不是数据本身?

which more or less just makes sure that I only have access to a copy, meaning that if I were to have two threads call a 'get' at the same time, they would each start with the same value of Field1 (right?). Is there a way to do read and write locking on a property that makes sense? Or should I just constrain myself to locking on sections of functions rather than the data itself?

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

Just so that this example makes sense: MyObject is a device driver that returns status asynchronously. I send it commands via a serial port, and then the device responds to those commands in its own sweet time. Right now, I have a thread that polls it for its status ("Are you still there? Can you accept commands?"), a thread that waits for responses on the serial port ("Just got status string 2, everything's all good"), and then the UI thread which takes in other commands ("User wants you to do this thing.") and posts the responses from the driver ("I've just done the thing, now update the UI with that"). That's why I want to lock on the object itself, rather than the fields of the object; that would be a huge number of locks, a, and b, not every device of this class has the same behavior, just general behavior, so I'd have to code lots of individual dialogs if I individualized the locks.

推荐答案

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

No, your code won't lock access to the members of the object returned from MyProperty. It only locks MyProperty itself.

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

Your example usage is really two operations rolled into one, roughly equivalent to this:

// 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 将暂时阻塞第二个线程,直到将对象返回给第一个线程,但是然后将对象也返回给第二个线程.然后,两个线程都将拥有对该对象的完全、未锁定的访问权限.

In a nutshell - if two threads access MyProperty simultaneously, the getter will briefly block the second thread until it returns the object to the first thread, but it'll then return the object to the second thread as well. Both threads will then have full, unlocked access to the object.

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

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

I'm still not 100% certain what you're trying to achieve, but if you just want atomic access to the object then couldn't you have the calling code lock against the object itself?

// 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) 部分中,那么这种方法就是线程安全的.

Not ideal, but so long as all access to the object is contained in lock (MyProperty) sections then this approach will be thread-safe.

这篇关于带有 get/set 的 C# 线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆