获取UI线程上的锁定

时间:2013-04-30 10:20:44

标签: c#

获取UI线程上的锁是一种不好的做法吗?例如,我有一个缓存对象,它被后台线程和UI线程修改。对缓存的任何修改都包含在锁中。伪代码如下:

 public class Cache
    {
        private readonly Dictionary<string, IEnumerable<string>> _cache;
        private readonly object _onCache = new object();
        public Cache()
        {
            _cache = new Dictionary<string, IEnumerable<string>>();
        }

        //Called by worker threads
        public void RefreshInBackground(IEnumerable<string> items, string key)
        {
            lock (_onCache)
            {
                _cache[key] = items;
            }
        }

        //Called by UI thread.Does this lead to any issues since UI thread is waiting on a lock?
        public void RefreshInForeground(IEnumerable<string> items, string key)
        {
            lock (_onCache)
            {
                _cache[key] = items;
            }
        }
    }

当UI线程调用RefreshInForegound时,它必须等待锁定(可能),问题是,这是不好的做法,如果是,为什么?

谢谢, -Mike

3 个答案:

答案 0 :(得分:3)

如果它工作得很好,我就不会改变它。

如果您有性能问题,那么您可以调整它。有些要改进的地方:

主要

  • 任何可能长时间运行的操作都应在非UI线程中执行。这意味着您需要从课程中删除RefreshInForeground并使用TaskThreadPoolBackgroundWorker等从UI运行RefreshInBackground

次要

  • 切换到Monitortry-finally,添加timeout。这仍然不是最佳选择,因为UI线程最多会在timeout的持续时间内被阻止。还是比永远等待更好。
  • 使用优化的储物柜,例如ReaderWriterLockSlim
  • 使用ConcurrentDictionary - 无锁或无阻塞类

答案 1 :(得分:1)

  

当UI线程调用RefreshInForegound时,它必须等待锁定(可能),问题是,这是不好的做法,如果是,为什么?

如果操作可能需要很长时间,则可能会出现问题,因为它会阻止UI。

如果使用相同锁定对象的所有操作都很短(例如示例中的简单字典设置器),我就不用担心了。

答案 2 :(得分:0)

对于字典,自.Net 4.0以来有ConcurrentDictionary个类。参见

Dictionary as thread-safe variable

对于其他类型的线程安全集合,您可能会看到http://msdn.microsoft.com/en-us/library/dd287108.aspx

对于锁定问题,这不是一个坏习惯。 lock关键字是在平凡的使用中管理并发的最方便的方法,但不是最优的。例如,如果您正在进行单写多次读取同步,ReaderWriterLock可能会更好。