[C#.NET][Thread] 執行緒單一寫入 / 多讀取資源鎖定 – ReaderWriterLock
ReaderWriterLock 類別,它允許同時間讓執行緒進行讀取,讓一條執行緒進行寫入,如果執行緒不常寫入,大部份的時間都在讀取,那使用它的效能會優於Monitor。
1.AcquireReaderLock 方法進入讀取鎖定,ReleaseReaderLock 方法解除讀取鎖定。
2.AcquireWriterLock 方法進入寫入鎖定,ReleaseWriterLock 方法解除寫入鎖定。
ReaderWriterLock 會保存讀取器鎖定和寫入器鎖定,但它們不會同時執行,我們來由下列的程式碼觀察:
1: private static ReaderWriterLock _rw = new ReaderWriterLock();
2: private static string _writer = "Empty";
3: private static List<Thread> _WriterThreads = new List<Thread>();
4: private static List<Thread> _ReaderThreads = new List<Thread>();
5: static void Main(string[] args)
6: {
7: for (int i = 0; i < 10; i++)
8: {
9: Thread reader = new Thread(new ThreadStart(Reader));//開10隻讀取器
10: reader.Start();
11: if (i < 2)//開2隻寫入器
12: {
13: Thread writer = new Thread(new ThreadStart(Writer));
14: writer.Start();
15: }
16: }
17:
18: Console.WriteLine("Main thread exist");
19: Console.ReadKey();
20: }
21:
22: public static void Reader()
23: {
24: try
25: {
26: _rw.AcquireReaderLock(Timeout.Infinite);
27: Thread t = Thread.CurrentThread;
28: Console.WriteLine("Thread[{0}]:{1},Read Value is {2}", t.ManagedThreadId, t.ThreadState, _writer);
29: Thread.Sleep(1000);
30: }
31: catch (Exception)
32: {
33: throw;
34: }
35: finally
36: {
37: _rw.ReleaseReaderLock();
38: }
39: }
40: public static void Writer()
41: {
42: try
43: {
44: _rw.AcquireWriterLock(Timeout.Infinite);
45: Thread t = Thread.CurrentThread;
46: int id = _rw.WriterSeqNum;
47: _writer = id.ToString();
48: Console.WriteLine("Thread[{0}]:{1},Write Value is {2}", t.ManagedThreadId, t.ThreadState, _writer);
49: }
50: catch (Exception)
51: {
52: throw;
53: }
54: finally
55: {
56: _rw.ReleaseWriterLock();
57: }
58: }
59:
如果仔細的觀察可以發現Read Value會同時間秀出來,Write Value會慢慢秀出來;讀取器和寫入器是個別佇列,ReaderWriterLock 會在讀取器集合和寫入器集合之間交替,兩者並不會同時執行。
我一直嘗試著要觀察他們之間的交替規則,但一直觀察不出來,看來是交由ReaderWriterLock 自行管理。
若要手動切到寫入器可利用
UpgradeToWriterLock 方法切換至寫入器鎖定狀態
DowngradeFromWriterLock 方法回到未切入到鎖定狀態
1: public static void Reader()
2: {
3: try
4: {
5: _rw.AcquireReaderLock(Timeout.Infinite);
6:
7: LockCookie cooke = _rw.UpgradeToWriterLock(Timeout.Infinite);
8:
9: Thread t = Thread.CurrentThread;
10: Console.WriteLine("Thread[{0}]:{1},Read Value is {2}", t.ManagedThreadId, t.ThreadState, _writer);
11: Thread.Sleep(1000);
12:
13: _rw.DowngradeFromWriterLock(ref cooke);
14:
15: }
16: catch (Exception)
17: {
18: throw;
19: }
20: finally
21: {
22: _rw.ReleaseReaderLock();
23: }
24: }
這樣的功能就像資料庫只能有一個人寫入一樣,是為了維護讀取者資料的一致性。
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET