【问题标题】:c# locking object shared by public methods and event callback codec#公共方法和事件回调代码共享的锁定对象
【发布时间】:2014-06-25 22:04:34
【问题描述】:

关于锁定的问题,文本参考下面的示例代码...我有一个类 (Class1),它提供了一个名为 Class1Resources 的公共 List 属性。 Class1 中的 2 个方法提供了对 Class1Resources 的基本查询能力。此外,Class1 还订阅了来自不同服务的事件,该服务提供 Class1 应更新此 Class1Resources 对象的通知。

我的问题是,应该在哪里实现锁定,以便在执行 ExternalAppCallback 时阻止查询 Class1Resources 的 2 个公共方法,从而确保查询方法始终使用最新数据?我在 ExternalAppCallback 中的注释代码是执行此操作的正确方法吗?

public class Class1
{
    public List<Resource> Class1Resources { get; private set; }

    public Class1()
    {
        // subscribe to external app event, with callback = ExternalAppCallback
    }

    private void ExternalAppCallback(List<Resource> updatedResourceList)
    {
        // do I put the lock here as in the code below?
        //lock(someObject)
        //{
        //    Class1Resources = new List<Resource>(updatedResourceList);
        //}

        Class1Resources = new List<Resource>(updatedResourceList);
    }

    public List<Resource> GetResourcesByCriteria1(string criteria1)
    {
        return Class1Resources.Where(r => r.Criteria1 == criteria1).ToList();
    }

    public List<Resource> GetResourcesByCriteria2(string criteria2)
    {
        return Class1Resources.Where(r => r.Criteria2 == criteria2).ToList();
    }
}

【问题讨论】:

  • 如果您的代码不是可重入的并且您不会有(太多)并发读取,那么一个简单的锁可能会很好地工作。当然,从我的 POV 来看,问题是 where ExternalAppCallback 被调用(从您发布的代码中,我没有看到任何简单的联锁操作无法解决的问题,但我猜当调用 ExternalAppCalback 调用时,会有一个很多工作要做)。
  • 如果我理解您的要求,简单的解决方案是此处显示的所有三种方法在尝试访问 Class1Resources 时都应共享一个锁,这将确保任何读取都完成在回调执行之前,反之亦然。

标签: c# synchronization locking


【解决方案1】:

我将您的问题解释为“我如何有效地使Class1Resources 线程安全?”所以我会推荐一个经典的lock,或者,如果你希望写入/更改很少,一个ReaderWriterLockSlim。以下是您如何在课堂上使用lock 来确保线程安全/一致的数据:

public class Class1
{
    // Here's your object to lock on
    private readonly object _lockObject = new object();

    // NOTE: made this private to control how it is exposed!
    private List<Resource> Class1Resources = null;

    public Class1()
    {
        // subscribe to external app event, with callback = ExternalAppCallback
    }

    private void ExternalAppCallback(List<Resource> updatedResourceList)
    {
        // Setting a reference is always atomic, no need to lock this
        Class1Resources = new List<Resource>(updatedResourceList);
    }

    // Your new method to expose the list in a thread-safe manner
    public List<Resource> GetResources()
    {
        lock (_lockObject)
        {
            // ToList() makes a copy of the list versus maintaining the original reference
            return Class1Resources.ToList();
        }

    }

    public List<Resource> GetResourcesByCriteria1(string criteria1)
    {
        lock (_lockObject)
        {
            return Class1Resources.Where(r => r.Criteria1 == criteria1).ToList();
        }
    }

    public List<Resource> GetResourcesByCriteria2(string criteria2)
    {
        lock (_lockObject)
        {
            return Class1Resources.Where(r => r.Criteria2 == criteria2).ToList();
        }
    }
}

请注意,在此解决方案中,任何调用您属性的 getter 的东西都不会使用锁,因此会导致线程安全问题。这就是我更改代码以使其成为私有成员的原因。

【讨论】:

  • 很抱歉延迟选择作为解决方案...出城几天没有服务...但非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-05
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多