加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 同步的IEnumerator

发布时间:2020-12-16 01:35:29 所属栏目:百科 来源:网络整理
导读:我正在整理一个自定义的SynchronizedCollection T class,以便我可以为我的 WPF应用程序提供一个同步的Observable集合.同步是通过ReaderWriterLockSlim提供的,在大多数情况下,它很容易应用.我遇到问题的情况是如何提供集合的线程安全枚举.我创建了一个自定义I
我正在整理一个自定义的SynchronizedCollection< T> class,以便我可以为我的 WPF应用程序提供一个同步的Observable集合.同步是通过ReaderWriterLockSlim提供的,在大多数情况下,它很容易应用.我遇到问题的情况是如何提供集合的线程安全枚举.我创建了一个自定义IEnumerator< T>嵌套类看起来像这样:

private class SynchronizedEnumerator : IEnumerator<T>
    {
        private SynchronizedCollection<T> _collection;
        private int _currentIndex;

        internal SynchronizedEnumerator(SynchronizedCollection<T> collection)
        {
            _collection = collection;
            _collection._lock.EnterReadLock();
            _currentIndex = -1;
        }

        #region IEnumerator<T> Members

        public T Current { get; private set;}

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            var collection = _collection;
            if (collection != null)
                collection._lock.ExitReadLock();

            _collection = null;
        }

        #endregion

        #region IEnumerator Members

        object System.Collections.IEnumerator.Current
        {
            get { return Current; }
        }

        public bool MoveNext()
        {
            var collection = _collection;
            if (collection == null)
                throw new ObjectDisposedException("SynchronizedEnumerator");

            _currentIndex++;
            if (_currentIndex >= collection.Count)
            {
                Current = default(T);
                return false;
            }

            Current = collection[_currentIndex];
            return true;
        }

        public void Reset()
        {
            if (_collection == null)
                throw new ObjectDisposedException("SynchronizedEnumerator");

            _currentIndex = -1;
            Current = default(T);
        }

        #endregion
    }

但是,我担心的是,如果Enumerator没有Disposed,那么锁永远不会被释放.在大多数用例中,这不是问题,因为foreach应该正确调用Dispose.但是,如果使用者检索显式的Enumerator实例,则可能会出现问题.我唯一的选择是使用一个警告实现者来记录该类,提醒消费者在明确使用Enumerator时调用Dispose,或者有没有办法在最终确定期间安全地释放锁定?我想不是,因为终结器甚至没有在同一个线程上运行,但我很好奇是否还有其他方法来改进它.

编辑

在考虑了这一点并阅读了回复之后(特别感谢Hans),我认为这绝对是一个坏主意.实际上,最大的问题不是忘记Dispose,而是一个悠闲的消费者在枚举时创造僵局.我现在只读取锁定足够长的时间来获取副本并返回副本的枚举器.

解决方法

你是对的,这是一个问题.终结器是没用的,它运行得太晚,无法使用.无论如何,代码应该在此之前严重陷入僵局.不幸的是,您无法区分调用MoveNext / Current成员的foreach或显式使用它们的客户端代码.

没有修复,不要这样做.微软也没有这样做,他们有充分的理由支持.NET 1.x.您可以创建的唯一真正的线程安全迭代器是在GetEnumerator()方法中创建集合对象的副本的迭代器.迭代器与集合不同步也不是快乐.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读