【问题标题】:Should all public class properties use "lock" in the MVC pattern?所有公共类属性都应该在 MVC 模式中使用“锁”吗?
【发布时间】:2016-03-06 20:44:00
【问题描述】:

在模型视图控制器(或模型视图视图-控制器)设计模式中,数据源和 UI 有单独的线程是很常见的。例如,假设有问题的应用程序是蓝牙 LE 温度计读取器。很自然的做法是让一个线程异步地从温度计获取数据,同时 UI 线程更新屏幕上的读数。

现在想象一个可以从一堆温度计中提取数据的应用。将TemperatureBattery Level 之类的东西包装到一个类中并将每个连接的设备作为该Thermometer 类的新实例是有意义的。但由于数据是从蓝牙设备异步到达每个设备的,因此 UI 线程可以在更新值时读取 Thermometer 的属性。

所以总的来说,在我看来,如果您的数据源位于与业务逻辑不同的线程上,每个访问器(get、set 等)都应该使用锁。这是真的?还是公共访问器中内置了一些线程安全性?如果没有,那么对每个 get/set 方法实施锁定似乎非常乏味,更不用说对于大型数据源效率低下。

【问题讨论】:

  • 锁定单个属性几乎总是错误的,因为它不能保证数据的一致性。您需要考虑您的应用程序中的“数据片段”意味着什么,并确保每次访问它时都以一致的方式完成。请注意,使用不可变数据结构使得考虑多线程代码更容易(不容易),因为一旦创建此类对象就不会改变,因此始终保持一致且线程安全。

标签: c# multithreading thread-safety


【解决方案1】:

不是 MVC 专家,但让我们看看您的示例。正如您正确识别的那样,您的模型是保存温度计数据的类或结构 - 称为Thermometer。您的控制器是轮询设备数据的可运行/线程,具有Thermometer 实例并负责更新它(我将其称为TemperatureProvider)。您的视图正在从控制器获取数据并生成要在 UI 上呈现的内容。到目前为止一切顺利,问题:

UI 线程可以在更新值时读取温度计的属性。

是的,但您可以通过 see this 进行读取操作。然而,建议在多线程环境中使用互斥锁。对于写操作,如果多个线程可以同时写,肯定需要加锁,这就引出了下一个问题:

或者公共访问器中是否内置了一些线程安全性?

不,我不知道...您必须自己实施锁定。但是,查看您的示例,我可以看到两种实现方式,具体取决于架构:

  1. 正如您所建议的,您可以在模型/Thermometer 中构建它,在这种情况下,getter/setter 将实现某种RW locking。这假设每个设备只存在一个Thermometer 实例

  2. 假设您的应用程序可以访问NTemperatureProviders,每个设备一个,那么您可以在控制器中实现锁定。我更喜欢这种方法,因为它保持数据结构完整并保持简单。此外,它允许您在不同的上下文中重用此结构,例如,时间戳 => Temperature 的列表/散列与不需要 RW 锁定的历史数据。

现在开始做一些不同的事情:您可以以不需要主线程或 UI 来轮询控制器的方式构建您的软件。据我了解MVC 模型,这些方法并没有破坏它:

  1. 通过使用像数据库这样的中间存储阶段(也将处理锁定)将设备轮询器与 UI/视图完全分离。在这种情况下,您的TemperatureProviders 正在更新表,而视图正在查询它。它们都使用相同的模型 (Thermometer) 来传输和存储数据,但具有不同的实例。

  2. 使用observer pattern(又名listenerspush/publish)。在这种情况下,不是 UI 轮询控制器,而是控制器“更新”/“通知” UI。您可以在 Java 中看到很多这种方法的示例(最常见的是 ActionListener)。

  3. 根据应用程序,有时Queue 对于传输消息非常有用。大多数语言都提供了可供使用的线程安全队列实现。这样您就不必实现锁定。在您的示例中,您可以在主线程中有一个队列,每个控制器在收到时都会推送新值。主线程只需检查队列是否有新的测量值。

如果您的问题是针对实际应用(而不是理论上的),我建议您采用观察者模式(但这主要是基于意见的)。

希望我没有让你厌烦:)

PS:我的术语可能不是来自 C#,而是来自其他语言...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 2011-03-12
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 2012-11-08
    • 1970-01-01
    相关资源
    最近更新 更多