3

在 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 时,它必须等待锁定(可能),问题是,这是一种不好的做法,如果是,为什么?

谢谢,-迈克

4

3 回答 3

4

如果它工作正常,我不会改变它。

如果您有性能问题,则可以对其进行调整。需要改进的几点:

主要的

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

次要的

  • 切换到Monitorand try-finally,添加timeout. 这仍然不是最佳选择,因为 UI 线程最多在timeout. 总比永远等待好。
  • 使用优化的储物柜,例如ReaderWriterLockSlim
  • 使用ConcurrentDictionary- 无锁或非阻塞类
于 2013-04-30T10:32:35.607 回答
1

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

如果操作可能需要很长时间,这可能是个问题,因为它会阻塞 UI。

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

于 2013-04-30T10:35:31.733 回答
0

ConcurrentDictionary对于字典,从 .Net 4.0 开始就有类。看

字典作为线程安全变量

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

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

于 2013-04-30T10:32:13.637 回答