亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

同步集合 InvalidOperationException/System

同步集合 InvalidOperationException/System

C#
泛舟湖上清波郎朗 2022-12-24 14:45:44
我編寫了一些類來使用SynchronizedCollection.class MultithreadTesting{    public readonly SynchronizedCollection<int> testlist = new SynchronizedCollection<int>();    public SynchronizedReadOnlyCollection<int> pubReadOnlyProperty    {        get        {            return new SynchronizedReadOnlyCollection<int>(testlist.SyncRoot, testlist);        }    }    public void Test()    {        int numthreads = 20;        Thread[] threads = new Thread[numthreads];        List<Task> taskList = new List<Task>();        for (int i = 0; i < numthreads / 2; i++)        {            taskList.Add(Task.Factory.StartNew(() =>            {                for (int j = 0; j < 100000; j++)                {                    testlist.Add(42);                }            }));        }        for (int i = numthreads / 2; i < numthreads; i++)        {            taskList.Add(Task.Factory.StartNew(() =>            {                var sum = 0;                foreach (int num in pubReadOnlyProperty)                {                    sum += num;                }            }));        }        Task.WaitAll(taskList.ToArray());        testlist.Clear();    }}運行它我使用    MultithreadTesting test = new MultithreadTesting();    while (true)        test.Test();但是代碼讓我失望System.ArgumentException: 'Destination array was not long enough. Check destIndex and length, and the array's lower bounds.'如果我嘗試使用testlistin foreach,我會得到System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'然而,MSDN 告訴我們SynchronizedReadOnlyCollection 類提供一個線程安全的只讀集合,其中包含泛型參數指定類型的對象作為元素。
查看完整描述

1 回答

?
MYYA

TA貢獻1868條經驗 獲得超4個贊

錯誤的根本原因是List<T>構造不是線程安全的。


讓我們看看在構造 new 時會發生什么SynchronizedReadOnlyCollection。異常發生在以下行:


return new SynchronizedReadOnlyCollection<int>(testlist.SyncRoot, testlist);

正如異常 StackTrace 告訴我們的那樣,List<T>..ctor在構建過程中涉及到:


at System.Collections.Generic.SynchronizedCollection`1.CopyTo(T[] array, Int32 index)

at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)

at System.Collections.Generic.SynchronizedReadOnlyCollection`1..ctor(Object syncRoot, IEnumerable`1 list)

構造函數中的以下片段List<T>顯示了錯誤發生的位置。代碼是從MS 參考源中復制的,我清理了代碼中不需要的部分以便于閱讀。請注意,在注釋 (1) 和 (2) 之間還有其他線程在操作集合:


public List(IEnumerable<T> collection) {

    ICollection<T> c = collection as ICollection<T>;

    // (1) count is now current Count of collection

    int count = c.Count;

    // other threads can modify collection meanwhile

    if (count == 0)

    {

        _items = _emptyArray;

    }

    else {

        _items = new T[count];

        // (2) SynchronizedCollection.CopyTo is called (which itself is thread-safe)

        // Collection can still be modified between (1) and (2) 

        // No when _items.Count != c.Count -> Exception is raised.

        c.CopyTo(_items, 0);

        _size = count;

    }

}

解決方案


testlist在構造 new 時,可以通過鎖定修改輕松解決該問題SynchronizedReadOnlyCollection。


public SynchronizedReadOnlyCollection<int> pubReadOnlyProperty

{

    get

    {

        lock (testlist.SyncRoot)

        {

            return new SynchronizedReadOnlyCollection<int>(testlist.SyncRoot, testlist);

        }

    }

}


查看完整回答
反對 回復 2022-12-24
  • 1 回答
  • 0 關注
  • 139 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號