C# 線程手冊 第三章 使用線程 ReaderWriterLock 類


一個ReaderWriterLock 類定義一個實現單寫多讀語義的鎖。這個類通常用在能被多個線程讀取但是僅能被一個線程寫入的文件操作時使用。下面是ReaderWriterLock類中的四個主要方法:

  a. AcquireReaderLock(): 這個重載方法獲取一個讀者鎖,接受一個整型或者TimeSpan類型的timeout 值。timeout是一個檢測死鎖的利器。

  b. AcquireWriterLock():  這個重載方法獲取一個寫者鎖,接受一個整型或者TimeSpan類型的timeout 值。

  c. ReleaseReaderLock(): 釋放讀者鎖。

  d. ReleaseWriterLock(): 釋放寫者鎖。

 

使用ReaderWriterLock類可以讓多線程安全地進行數據並發讀取。只有當線程正在更新的數據鎖定。讀者線程可以再沒有寫者擁有鎖的時候獲得鎖。寫者線程可以再沒有讀者線程或者寫者線程擁有鎖的時候獲得鎖。

下面的列表ReadeWriteLock.cs, 描述了如何使用ReaderWriterLock()鎖:

/*************************************
/* copyright (c) 2012 daniel dong
 * 
 * author:daniel dong
 * blog:  www.cnblogs.com/danielwise
 * email: guofoo@163.com
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ReadWriteLock
{
    public class ReadWrite
    {
        private ReaderWriterLock rwl;
        private int x;
        private int y;

        public ReadWrite()
        {
            rwl = new ReaderWriterLock();
        }

        public void ReadInts(ref int a, ref int b)
        {
            rwl.AcquireReaderLock(Timeout.Infinite);
            try
            {
                a = this.x;
                b = this.y;
            }
            finally
            {
                rwl.ReleaseReaderLock();
            }
        }

        public void WriteInts(int a, int b)
        {
            rwl.AcquireWriterLock(Timeout.Infinite);
            try
            {
                this.x = a;
                this.y = b;
                Console.WriteLine("x = " + this.x
                    + " y = " + this.y
                    + " ThreadID = " + Thread.CurrentThread.GetHashCode());
            }
            finally
            {
                rwl.ReleaseWriterLock();
            }
        }
    }

    public class RWApp
    {
        private ReadWrite rw = new ReadWrite();

        public static void Main(string[] args)
        {
            RWApp e = new RWApp();

            //Writer Threads
            Thread wt1 = new Thread(new ThreadStart(e.Write));
            wt1.Start();
            Thread wt2 = new Thread(new ThreadStart(e.Write));
            wt2.Start();

            //Reader Threads
            Thread rt1 = new Thread(new ThreadStart(e.Read));
            rt1.Start();
            Thread rt2 = new Thread(new ThreadStart(e.Read));
            rt2.Start();

            Console.ReadLine();
        }

        private void Write()
        {
            int a = 10;
            int b = 11;
            Console.WriteLine("************** Write *************");

            for (int i = 0; i < 5; i++)
            {
                this.rw.WriteInts(a++, b++);
                Thread.Sleep(1000);
            }
        }

        private void Read()
        {
            int a = 10;
            int b = 11;
            Console.WriteLine("************** Read *************");

            for (int i = 0; i < 5; i++)
            {
                this.rw.ReadInts(ref a, ref b);
                Console.WriteLine("For i = " + i
                    + " a = " + a
                    + " b = " + b
                    + " TheadID = " + Thread.CurrentThread.GetHashCode());
                Thread.Sleep(1000);
            }
        }
    }
}

ReadWriteLock 的輸出結果可能與下表類似:

ReaderWriterLock

在上面的列表中,線程wt1 和 wt2 是WriteInts()方法中獲得寫鎖的寫者線程,線程rt1 和 rt2 是在ReadInts()方法中獲得讀者鎖的讀者線程。在WriteInts()方法中,變量x 和 y 的值分別被改成a 和 b. 當線程wt1 或 wt2 通過調用AcquireWriterLock() 方法獲得一個寫者鎖后,那么直到這個線程通過調用ReleaseWriterLock()方法釋放鎖之前任何其他線程(包括讀者線程rt1 和 rt2)都不被允許訪問相應對象。這個行為與Monitors類似 。在ReadInts()方法中,線程rt1 和 rt2 通過調用AcquireReaderLock()方法獲得讀者鎖, 這兩個線程可以並發地訪問變量x 和 y. 直到讀者線程釋放它們的讀者鎖以后,寫者線程(wt1 和 wt2)才被允許訪問對應對象。只有讀者線程在獲得讀者鎖以后才可以並發地訪問。

Monitors類對於只想來讀數據而非寫數據來說過於“安全”了。Monitors 也有一些性能問題,對於只讀類型的訪問來說,性能瓶頸是可以避免的。ReaderWriterLock類通過允許任意數量的線程並發地讀取數據來提供一個解決數據讀-寫問題的完美方案。當線程更新數據時鎖住數據。當沒有寫者線程擁有鎖的時候寫者線程可以獲得鎖。寫者鎖可以在沒有讀者線程或者寫者線程擁有鎖的時候獲得鎖。因此,ReaderWriterLock 就像是一段關鍵部分代碼, 它也支持一個timeout 值,而這方面在檢測死鎖時非常有用。

 

下一篇介紹手動同步…


免責聲明!

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



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