【问题标题】:Best practice to lock data objects锁定数据对象的最佳实践
【发布时间】:2017-02-16 09:10:09
【问题描述】:

我编写了一个处理大型文本文件的应用程序。在内部,文本文件存储为 DataObject,其中包含多个数据,例如文件的行、文件路径等。我可以使用应用程序修改这些文件(分别是数据对象)。因为有些方法很耗时,所以我在 Task 中运行它们以避免阻塞 UI。现在,使用非阻塞 UI,我想确保用户不会尝试修改当前正在任务中处理的文件,因此我想锁定 DataObject。为此,我认为我可以向 DataObject 类添加一个锁对象。然后我会以这种方式锁定 DataObject:

public class DataObject {
    public object LockObject = new object();
    // ...

    public DataObject() { }
}

public void timeConsumingMethod(DataObject data) {
    Task.Factory.StartNew(new Action(() => {
        lock(data.LockObject) {
            // do work
        }
    }));
}

这是要走的路吗?还是有更好的办法?

【问题讨论】:

  • 我喜欢建议的解决方案,如果您尝试从对象中读取,我会小心 - 这可能会导致同时写入/读取的问题(或者如果您在阅读时忘记锁定它) .我会添加我自己的问题,询问是否应该在 getting/setting 值时在属性内完成锁定?
  • 考虑使用Task.Run 而不是StartNew,即is dangerous
  • @VMAtm:我已经阅读了这篇文章。很好的博客。我还没有考虑过。谢谢

标签: c# multithreading locking task


【解决方案1】:

永远不要暴露 LockObject,隐藏实现细节:

private object m_LockObject = new object();

下一期:为什么timeConsumingMethod 收到DataObject 而不是 在DataObject内实现:

public class DataObject {
  // locking object is a private implementation detail
  private object m_LockObject = new object();

  // TheMethod works with "this" DataObject instance, that's why
  // the method belongs to DataObject
  // let's return Task (e.g. to await it)
  // Think on method's name; 
  public Task TheMethodAsync() {
    // Task.Factory.StartNew is evil
    return Task.Run(() => {
      lock (m_LockObject) {
        // ...
      } 
    });
  }

  ...
}

然后调用方法

 public void timeConsumingMethod(DataObject data) {
   // When designing public methods do not forget about validation
   if (null == data)
     throw new ArgumentNullException("data");

   // Think on awaiting the Task returned:
   // "i run them in a Taks ... to avoid blocking the UI"
   // await data.TheMethodAsync();  
   data.TheMethodAsync();  

   ...
 }

【讨论】:

  • 我不想在 DataObject 中实现该方法,因为我有很多这样的方法,我想避免膨胀 DataObject。不管这种方式,我很感兴趣是否有一个好的解决方案而不实现 DataObject 中的所有方法。
  • 好吧,作为妥协,我可以使用扩展方法。这不会使 DataObject 膨胀,而且我能够保持我的代码干净整洁。
  • @ooorndtski: 如果DataObject 太大,似乎是DataObject 设计问题。是否可以从DataObject 中提取一些类?
  • @ooorndtski:当您无法更改目标对象(通常是标准库之一,例如string)时,扩展方法是一种很好的做法。如果您实际上可以重新设计 DataObject 实现 扩展方法 只会带来不必要的复杂性。
  • 好的,非常感谢。在考虑了您的帖子后,我决定重新设计我的应用程序。修改 DataObject 实例的方法已添加到 DataObject。
猜你喜欢
  • 2016-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-04
  • 2023-03-25
  • 2013-03-23
  • 1970-01-01
相关资源
最近更新 更多