C# 在多線程環境中,進行安全遍歷操作


本文以List作為操作對象
MSDN官方給出的List的線程安全的說法:
此類型的公共靜態成員是線程安全的。但不能保證任何實例成員是線程安全的。
只要不修改該集合,List 就可以同時支持多個閱讀器。通過集合枚舉在本質上不是一個線程安全的過程。在枚舉與一個或多個寫訪問競爭的罕見情況下,確保線程安全的唯一方法是在整個枚舉期間鎖定集合。若要允許多個線程訪問集合以進行讀寫操作,則必須實現自己的同步。
如果不進行同步操作?
假如一個線程進行刪除操作,一個線程進行遍歷操作,那么在遍歷過程中,集合被修改,會導致出現InvalidOperationException的異常,提示:集合已修改;可能無法執行枚舉操作。
如何同步,保證遍歷的安全
這里使用了臨界區,互斥鎖來保證線程遍歷過程的安全,示例代碼如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Threading;
 4 
 5 namespace ConsoleApp
 6 {
 7     class Program
 8     {
 9         public static List<string> simpleList = new List<string>();
10         
11         public static void Main(string[] args)
12         {
13             // 臨界區對象
14             object lockObj = new object();
15 
16             // 向List中添加測試數據
17             string[] data = { "1", "2", "3", "4", "5", "6", "7", "8" };
18             simpleList.AddRange(data);
19             // 此線程用於遍歷數組
20             new Thread(new ThreadStart(() =>
21             {
22                 // 用於同步,進入臨界區,只有遍歷完,釋放臨界區對象的互斥鎖,才能進行寫操作
23                 lock (lockObj)
24                 {
25                     foreach (var item in simpleList)
26                     {
27                         Console.WriteLine(item);
28                         Thread.Sleep(500);
29                     }
30                 }
31             })).Start();
32             // 此線程執行刪除操作
33             new Thread(new ThreadStart(() =>
34             {
35                 lock (lockObj)
36                 {
37                     simpleList.RemoveAt(0);
38                     Console.WriteLine("rm 1");
39                     Thread.Sleep(500);
40                     simpleList.RemoveAt(0);
41                     Console.WriteLine("rm 2");
42                 }
43             })).Start();
44 
45             Console.ReadLine();
46         }
47     }
48 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM