c#锁定对象由公共方法和事件回调代码共享

时间:2014-06-25 22:04:34

标签: c# synchronization locking

有关锁定的问题,文本引用下面的示例代码...我有一个类(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();
    }
}

1 个答案:

答案 0 :(得分:0)

我将您的问题解释为“我如何有效地使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的任何内容都不会使用锁,因此会导致线程安全问题。这就是我更改代码以使其成为私有成员的原因。