多核時代.NETFramework4中的並行程式設計9—執行緒安全集合類

技術小胖子發表於2017-11-07

.Net 4中,新增System.Collections.Concurrent 名稱空間中提供多個執行緒安全集合類,這些類提供了很多有用的方法用於訪問集合中的元素,從而可以避免使用傳統的鎖(lock)機制等方式來處理併發訪問集合.因此當有多個執行緒併發訪問集合時,應首先考慮使用這些類代替 System.Collections 和 System.Collections.Generic 名稱空間中的對應型別.具體如下:

1. ConcurrentQueue

表示執行緒安全的先進先出(FIFO)佇列.程式碼如下:

           ConcurrentQueue<int> sharedQueue = new ConcurrentQueue<int>();

            for (int i = 0; i < 1000; i++)

            {

                sharedQueue.Enqueue(i);

            }

 

            int itemCount = 0;

 

            Task[] tasks = new Task[10];

            for (int i = 0; i < tasks.Length; i++)

            {

                tasks[i] = new Task(() =>

                {

                    while (sharedQueue.Count > 0)

                    {

                        int queueElement;

                        bool gotElement = sharedQueue.TryDequeue(outqueueElement);

                        if (gotElement)

                        {

                            Interlocked.Increment(ref itemCount);

                        }

                    }

 

                });

                tasks[i].Start();

            }

 

            Task.WaitAll(tasks);

 

            Console.WriteLine(“Items processed:{0}”, itemCount);

            Console.WriteLine(“Press Enter to finish”);

            Console.ReadLine();

該類有兩個重要的方法用來訪問佇列中的元素.分別是:

Ø TryDequeue 嘗試移除並返回位於佇列頭開始處的物件.

Ø TryPeek嘗試返回位於佇列頭開始處的物件但不將其移除.

現在,在多工訪問集合元素時,我們只需要使用TryDequeue或TryPeek方法,就可以安全的訪問集合中的元素了.

2. ConcurrentStack

表示執行緒安全的後進先出(LIFO)棧.它也有幾個有用的方法,分別是:

Ø TryPeek:嘗試返回棧頂處的元素,但不移除.

Ø TryPop: 嘗試返回棧頂處的元素並移除.

Ø TryPopRange: 嘗試返回棧頂處開始指定範圍的元素並移除.

在訪問集合中的元素時,我們就可以上述方法.具體程式碼例項於上面的ConcurrentQueue類似,就不重複了.

3. ConcurrentBag

實現的是一個無序的集合類.程式碼如下:

            ConcurrentBag<int> sharedBag = new ConcurrentBag<int>();

            for (int i = 0; i < 1000; i++)

            {

                sharedBag.Add(i);

            }

 

            int itemCount = 0;

            Task[] tasks = new Task[10];

            for (int i = 0; i < tasks.Length; i++)

            {

                tasks[i] = new Task(() =>

                {

                   while(sharedBag.Count>0)

                    {

                        int queueElement;

                        bool gotElement = sharedBag.TryTake(outqueueElement);

                       if (gotElement)

                            Interlocked.Increment(ref itemCount);

                    }

                });

 

                tasks[i].Start();

            }

 

            Task.WaitAll(tasks);

 

            Console.WriteLine(“Items processed:{0}”, itemCount);

            Console.WriteLine(“Press Enter to finish”);

            Console.ReadLine();

該類有兩個重要的方法用來訪問佇列中的元素.分別是:

Ø TryTake 嘗試移除並返回位於佇列頭開始處的物件.

Ø TryPeek嘗試返回位於佇列頭開始處的物件但不將其移除.

4. ConcurrentDictionary

實現的是一個鍵-值集合類.它提供的方法有:

Ø TryAdd:嘗試向集合新增一個鍵-值

Ø TryGetValue:嘗試返回指定鍵的值.

Ø TryRemove:嘗試移除指定鍵處的元素.

Ø TryUpdate:嘗試更新指定鍵的值.

程式碼如下:

        class BankAccount

        {

            public int Balance

            {

                get;

                set;

            }

        }

 

 static void DictTest()

        {

            BankAccount account = new BankAccount();

            ConcurrentDictionary<objectint> sharedDict = newConcurrentDictionary<objectint>();

 

            Task<int>[] tasks = new Task<int>[10];

            for (int i = 0; i < tasks.Length; i++)

            {

                sharedDict.TryAdd(i, account.Balance);

                tasks[i] = new Task<int>((keyObj) =>

                {

                    int currentValue;

                    bool gotValue;

                    for (int j = 0; j < 1000; j++)

                    {

                        gotValue = sharedDict.TryGetValue(keyObj, outcurrentValue);

                        sharedDict.TryUpdate(keyObj, currentValue + 1, currentValue);

                    }

                    int result;

                    gotValue = sharedDict.TryGetValue(keyObj, outresult);

                    if (gotValue)

                    {

                        return result;

                    }

                    else

                    {

                        throw new Exception(String.Format(“No data item available for key {0}”, keyObj));

                    }

                }, i);

                tasks[i].Start();

            }

            for (int i = 0; i < tasks.Length; i++)

            {

                account.Balance += tasks[i].Result;

            }

 

            Console.WriteLine(“Expected value {0}, Balance: {1}”, 10000, account.Balance);

            Console.WriteLine(“Press enter to finish”);

            Console.ReadLine();

}

通過上述提供的安全類,我們可以方便的併發訪問集合中的元素,而不需要以前的Synchronized方法或者lock(SyncRoot)等處理方式.



    本文轉自風車車  部落格園部落格,原文連結:http://www.cnblogs.com/xray2005/archive/2011/10/11/2206745.html,如需轉載請自行聯絡原作者




相關文章