欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#使用讀寫鎖解決多線程并發(fā)問題

 更新時間:2022年04月18日 10:02:55   作者:農(nóng)碼一生  
本文詳細講解了C#使用讀寫鎖解決多線程并發(fā)問題,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

一、簡介

在開發(fā)程序的過程中,難免少不了寫入錯誤日志這個關鍵功能。實現(xiàn)這個功能,可以選擇使用第三方日志插件,也可以選擇使用數(shù)據(jù)庫,還可以自己寫個簡單的方法把錯誤信息記錄到日志文件?,F(xiàn)在我們來講下最后一種方法:

在選擇最后一種方法實現(xiàn)的時候,若對文件操作與線程同步不熟悉,問題就有可能出現(xiàn)了,因為同一個文件并不允許多個線程同時寫入,否則會提示“文件正在由另一進程使用,因此該進程無法訪問此文件”。這是文件的并發(fā)寫入問題,就需要用到線程同步。而微軟也給線程同步提供了一些相關的類可以達到這樣的目的,本文使用到的 System.Threading.ReaderWriterLockSlim 便是其中之一。該類用于管理資源訪問的鎖定狀態(tài),可實現(xiàn)多線程讀取或進行獨占式寫入訪問。利用這個類,我們就可以避免在同一時間段內多線程同時寫入一個文件而導致的并發(fā)寫入問題。讀寫鎖是以 ReaderWriterLockSlim 對象作為鎖管理資源的,不同的 ReaderWriterLockSlim 對象中鎖定同一個文件也會被視為不同的鎖進行管理,這種差異可能會再次導致文件的并發(fā)寫入問題,所以 ReaderWriterLockSlim 應盡量定義為只讀的靜態(tài)對象。
ReaderWriterLockSlim 有幾個關鍵的方法,本文僅討論寫入鎖:

1.調用 EnterWriteLock 方法 進入寫入狀態(tài),在調用線程進入鎖定狀態(tài)之前一直處于阻塞狀態(tài),因此可能永遠都不返回。
2.調用 TryEnterWriteLock 方法 進入寫入狀態(tài),可指定阻塞的間隔時間,如果調用線程在此間隔期間并未進入寫入模式,將返回false。
3.調用 ExitWriteLock 方法 退出寫入狀態(tài),應使用 finally 塊執(zhí)行 ExitWriteLock 方法,從而確保調用方退出寫入模式。

二、不使用讀寫鎖寫入文件:

代碼:

class Program
    {
        static int LogCount = 100;
        static int WritedCount = 0;
        static int FailedCount = 0;
        static void Main(string[] args)
        {
            //迭代運行寫入日志記錄,由于多個線程同時寫入同一個文件將會導致錯誤
            Parallel.For(0, LogCount, e =>
            {
                WriteLog1();
            });
            Console.WriteLine(string.Format("\r\nLog Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
            Console.Read();
        }
        #region 未加入讀寫鎖
        //不使用讀寫鎖寫入文件
        static void WriteLog1()
        {
            try
            {
                var logFilePath = "log.txt";
                var now = DateTime.Now;
                var logContent = string.Format("Tid: {0}{1} {2}.{3}\r\n", Thread.CurrentThread.ManagedThreadId.ToString().PadRight(4), now.ToLongDateString(), now.ToLongTimeString(), now.Millisecond.ToString());
                File.AppendAllText(logFilePath, logContent);
                WritedCount++;
            }
            catch (Exception ex)
            {
                FailedCount++;
                Console.WriteLine(ex.Message);
            }
        }
        #endregion
    }

運行結果:

不是所有的log都能寫入到log.txt,因為不適用讀寫錯可能會出現(xiàn)上面提到的:“文件正在由另一進程使用,因此該進程無法訪問此文件”報錯信息。

記錄log信息:

Tid: 9   2021年5月21日 下午 02:18:04.919
Tid: 9   2021年5月21日 下午 02:18:04.944
Tid: 9   2021年5月21日 下午 02:18:05.80
Tid: 11  2021年5月21日 下午 02:18:05.81
Tid: 9   2021年5月21日 下午 02:18:05.82
Tid: 12  2021年5月21日 下午 02:18:05.83
Tid: 11  2021年5月21日 下午 02:18:05.84
Tid: 12  2021年5月21日 下午 02:18:05.84
Tid: 16  2021年5月21日 下午 02:18:05.85
Tid: 12  2021年5月21日 下午 02:18:05.111
Tid: 16  2021年5月21日 下午 02:18:05.117
Tid: 16  2021年5月21日 下午 02:18:05.128
Tid: 11  2021年5月21日 下午 02:18:05.128
Tid: 16  2021年5月21日 下午 02:18:05.133
Tid: 12  2021年5月21日 下午 02:18:05.138
Tid: 16  2021年5月21日 下午 02:18:05.140
Tid: 12  2021年5月21日 下午 02:18:05.140
Tid: 16  2021年5月21日 下午 02:18:05.142
Tid: 16  2021年5月21日 下午 02:18:05.144
Tid: 16  2021年5月21日 下午 02:18:05.151
Tid: 16  2021年5月21日 下午 02:18:05.158
Tid: 9   2021年5月21日 下午 02:18:05.159
Tid: 10  2021年5月21日 下午 02:18:05.159
Tid: 9   2021年5月21日 下午 02:18:05.164
Tid: 16  2021年5月21日 下午 02:18:05.164
Tid: 9   2021年5月21日 下午 02:18:05.172
Tid: 15  2021年5月21日 下午 02:18:05.172
Tid: 16  2021年5月21日 下午 02:18:05.181
Tid: 16  2021年5月21日 下午 02:18:05.187
Tid: 15  2021年5月21日 下午 02:18:05.188
Tid: 16  2021年5月21日 下午 02:18:05.195
Tid: 16  2021年5月21日 下午 02:18:05.196
Tid: 15  2021年5月21日 下午 02:18:05.195
Tid: 16  2021年5月21日 下午 02:18:05.202
Tid: 16  2021年5月21日 下午 02:18:05.203
Tid: 15  2021年5月21日 下午 02:18:05.202
Tid: 15  2021年5月21日 下午 02:18:05.207
Tid: 15  2021年5月21日 下午 02:18:05.209
Tid: 16  2021年5月21日 下午 02:18:05.207
Tid: 15  2021年5月21日 下午 02:18:05.210
Tid: 15  2021年5月21日 下午 02:18:05.222
Tid: 15  2021年5月21日 下午 02:18:05.231
Tid: 18  2021年5月21日 下午 02:18:05.238
Tid: 15  2021年5月21日 下午 02:18:05.238
Tid: 18  2021年5月21日 下午 02:18:05.244
Tid: 15  2021年5月21日 下午 02:18:05.251
Tid: 15  2021年5月21日 下午 02:18:05.256
Tid: 15  2021年5月21日 下午 02:18:05.262
Tid: 15  2021年5月21日 下午 02:18:05.304
Tid: 15  2021年5月21日 下午 02:18:05.312
Tid: 13  2021年5月21日 下午 02:18:05.312
Tid: 9   2021年5月21日 下午 02:18:05.313
Tid: 13  2021年5月21日 下午 02:18:05.320
Tid: 19  2021年5月21日 下午 02:18:05.320
Tid: 16  2021年5月21日 下午 02:18:05.325
Tid: 19  2021年5月21日 下午 02:18:05.333
Tid: 16  2021年5月21日 下午 02:18:05.342
Tid: 16  2021年5月21日 下午 02:18:05.349
Tid: 16  2021年5月21日 下午 02:18:05.361
Tid: 16  2021年5月21日 下午 02:18:05.366
Tid: 16  2021年5月21日 下午 02:18:05.367
Tid: 16  2021年5月21日 下午 02:18:05.368
Tid: 16  2021年5月21日 下午 02:18:05.376
Tid: 16  2021年5月21日 下午 02:18:05.386
Tid: 16  2021年5月21日 下午 02:18:05.392
Tid: 16  2021年5月21日 下午 02:18:05.401
Tid: 9   2021年5月21日 下午 02:18:05.463
Tid: 13  2021年5月21日 下午 02:18:05.464
Tid: 15  2021年5月21日 下午 02:18:05.464
Tid: 13  2021年5月21日 下午 02:18:05.465
Tid: 13  2021年5月21日 下午 02:18:05.470
Tid: 11  2021年5月21日 下午 02:18:05.479

三、使用讀寫鎖寫入文件:

代碼:

class Program
    {
        static int LogCount = 100;
        static int WritedCount = 0;
        static int FailedCount = 0;
        static void Main(string[] args)
        {
            //迭代運行寫入日志記錄,由于多個線程同時寫入同一個文件將會導致錯誤
            Parallel.For(0, LogCount, e =>
            {
                WriteLog2();
            });
            Console.WriteLine(string.Format("\r\nLog Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
            Console.Read();
        }
        #region 加入讀寫鎖
        //讀寫鎖,當資源處于寫入模式時,其他線程寫入需要等待本次寫入結束之后才能繼續(xù)寫入
        static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
        static void WriteLog2()
        {
            try
            {
                //設置讀寫鎖為寫入模式獨占資源,其他寫入請求需要等待本次寫入結束之后才能繼續(xù)寫入
                //注意:長時間持有讀線程鎖或寫線程鎖會使其他線程發(fā)生饑餓 (starve)。 為了得到最好的性能,需要考慮重新構造應用程序以將寫訪問的持續(xù)時間減少到最小。
                //從性能方面考慮,請求進入寫入模式應該緊跟文件操作之前,在此處進入寫入模式僅是為了降低代碼復雜度
                //因進入與退出寫入模式應在同一個try finally語句塊內,所以在請求進入寫入模式之前不能觸發(fā)異常,否則釋放次數(shù)大于請求次數(shù)將會觸發(fā)異常
                LogWriteLock.EnterWriteLock();
                var logFilePath = "log.txt";
                var now = DateTime.Now;
                var logContent = string.Format("Tid: {0}{1} {2}.{3}\r\n", Thread.CurrentThread.ManagedThreadId.ToString().PadRight(4), now.ToLongDateString(), now.ToLongTimeString(), now.Millisecond.ToString());

                File.AppendAllText(logFilePath, logContent);
                WritedCount++;
            }
            catch (Exception)
            {
                FailedCount++;
            }
            finally
            {
                //退出寫入模式,釋放資源占用
                //注意:一次請求對應一次釋放
                //若釋放次數(shù)大于請求次數(shù)將會觸發(fā)異常[寫入鎖定未經(jīng)保持即被釋放]
                //若請求處理完成后未釋放將會觸發(fā)異常[此模式不下允許以遞歸方式獲取寫入鎖定]
                LogWriteLock.ExitWriteLock();
            }
        }
        #endregion
    }

運行結果:

所有的log都完全正確寫入到log.txt。

記錄log信息:

Tid: 8   2021年5月21日 下午 02:26:36.573
Tid: 8   2021年5月21日 下午 02:26:36.597
Tid: 8   2021年5月21日 下午 02:26:36.599
Tid: 8   2021年5月21日 下午 02:26:36.600
Tid: 8   2021年5月21日 下午 02:26:36.601
Tid: 8   2021年5月21日 下午 02:26:36.602
Tid: 8   2021年5月21日 下午 02:26:36.608
Tid: 8   2021年5月21日 下午 02:26:36.609
Tid: 8   2021年5月21日 下午 02:26:36.614
Tid: 8   2021年5月21日 下午 02:26:36.616
Tid: 8   2021年5月21日 下午 02:26:36.617
Tid: 8   2021年5月21日 下午 02:26:36.620
Tid: 8   2021年5月21日 下午 02:26:36.620
Tid: 8   2021年5月21日 下午 02:26:36.621
Tid: 8   2021年5月21日 下午 02:26:36.622
Tid: 8   2021年5月21日 下午 02:26:36.623
Tid: 8   2021年5月21日 下午 02:26:36.624
Tid: 8   2021年5月21日 下午 02:26:36.624
Tid: 8   2021年5月21日 下午 02:26:36.625
Tid: 8   2021年5月21日 下午 02:26:36.626
Tid: 8   2021年5月21日 下午 02:26:36.626
Tid: 8   2021年5月21日 下午 02:26:36.627
Tid: 8   2021年5月21日 下午 02:26:36.628
Tid: 8   2021年5月21日 下午 02:26:36.628
Tid: 8   2021年5月21日 下午 02:26:36.629
Tid: 8   2021年5月21日 下午 02:26:36.630
Tid: 8   2021年5月21日 下午 02:26:36.630
Tid: 8   2021年5月21日 下午 02:26:36.631
Tid: 8   2021年5月21日 下午 02:26:36.632
Tid: 8   2021年5月21日 下午 02:26:36.632
Tid: 8   2021年5月21日 下午 02:26:36.633
Tid: 8   2021年5月21日 下午 02:26:36.634
Tid: 8   2021年5月21日 下午 02:26:36.634
Tid: 8   2021年5月21日 下午 02:26:36.635
Tid: 8   2021年5月21日 下午 02:26:36.636
Tid: 8   2021年5月21日 下午 02:26:36.636
Tid: 8   2021年5月21日 下午 02:26:36.637
Tid: 8   2021年5月21日 下午 02:26:36.638
Tid: 8   2021年5月21日 下午 02:26:36.638
Tid: 8   2021年5月21日 下午 02:26:36.639
Tid: 8   2021年5月21日 下午 02:26:36.641
Tid: 8   2021年5月21日 下午 02:26:36.641
Tid: 8   2021年5月21日 下午 02:26:36.642
Tid: 8   2021年5月21日 下午 02:26:36.643
Tid: 8   2021年5月21日 下午 02:26:36.644
Tid: 8   2021年5月21日 下午 02:26:36.644
Tid: 8   2021年5月21日 下午 02:26:36.645
Tid: 8   2021年5月21日 下午 02:26:36.646
Tid: 8   2021年5月21日 下午 02:26:36.647
Tid: 8   2021年5月21日 下午 02:26:36.647
Tid: 8   2021年5月21日 下午 02:26:36.648
Tid: 8   2021年5月21日 下午 02:26:36.649
Tid: 8   2021年5月21日 下午 02:26:36.650
Tid: 8   2021年5月21日 下午 02:26:36.650
Tid: 8   2021年5月21日 下午 02:26:36.651
Tid: 8   2021年5月21日 下午 02:26:36.652
Tid: 8   2021年5月21日 下午 02:26:36.652
Tid: 8   2021年5月21日 下午 02:26:36.652
Tid: 8   2021年5月21日 下午 02:26:36.653
Tid: 8   2021年5月21日 下午 02:26:36.654
Tid: 8   2021年5月21日 下午 02:26:36.655
Tid: 8   2021年5月21日 下午 02:26:36.656
Tid: 8   2021年5月21日 下午 02:26:36.658
Tid: 8   2021年5月21日 下午 02:26:36.658
Tid: 8   2021年5月21日 下午 02:26:36.659
Tid: 8   2021年5月21日 下午 02:26:36.660
Tid: 8   2021年5月21日 下午 02:26:36.660
Tid: 8   2021年5月21日 下午 02:26:36.661
Tid: 8   2021年5月21日 下午 02:26:36.662
Tid: 8   2021年5月21日 下午 02:26:36.662
Tid: 8   2021年5月21日 下午 02:26:36.663
Tid: 8   2021年5月21日 下午 02:26:36.664
Tid: 8   2021年5月21日 下午 02:26:36.664
Tid: 8   2021年5月21日 下午 02:26:36.665
Tid: 8   2021年5月21日 下午 02:26:36.666
Tid: 8   2021年5月21日 下午 02:26:36.666
Tid: 8   2021年5月21日 下午 02:26:36.667
Tid: 8   2021年5月21日 下午 02:26:36.668
Tid: 8   2021年5月21日 下午 02:26:36.669
Tid: 8   2021年5月21日 下午 02:26:36.669
Tid: 8   2021年5月21日 下午 02:26:36.670
Tid: 8   2021年5月21日 下午 02:26:36.671
Tid: 8   2021年5月21日 下午 02:26:36.672
Tid: 8   2021年5月21日 下午 02:26:36.673
Tid: 8   2021年5月21日 下午 02:26:36.675
Tid: 8   2021年5月21日 下午 02:26:36.675
Tid: 8   2021年5月21日 下午 02:26:36.676
Tid: 8   2021年5月21日 下午 02:26:36.677
Tid: 14  2021年5月21日 下午 02:26:36.678
Tid: 15  2021年5月21日 下午 02:26:36.679
Tid: 16  2021年5月21日 下午 02:26:36.680
Tid: 17  2021年5月21日 下午 02:26:36.681
Tid: 18  2021年5月21日 下午 02:26:36.681
Tid: 20  2021年5月21日 下午 02:26:36.683
Tid: 9   2021年5月21日 下午 02:26:36.683
Tid: 19  2021年5月21日 下午 02:26:36.684
Tid: 10  2021年5月21日 下午 02:26:36.685
Tid: 11  2021年5月21日 下午 02:26:36.685
Tid: 12  2021年5月21日 下午 02:26:36.687
Tid: 13  2021年5月21日 下午 02:26:36.688

到此這篇關于C#使用讀寫鎖解決多線程并發(fā)問題的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • C#實現(xiàn)對象序列化的3種方案小結

    C#實現(xiàn)對象序列化的3種方案小結

    在上位機開發(fā)過程中,我們可能經(jīng)常要實現(xiàn)一個數(shù)據(jù)對象的持久化,本文主要介紹了C#實現(xiàn)對象序列化的3種方案,具有一定的參考價值,感興趣的可以了解一下
    2025-01-01
  • C# WinForm制作異形窗體與控件的方法

    C# WinForm制作異形窗體與控件的方法

    這篇文章主要介紹了C# WinForm制作異形窗體與控件的方法,結合實例形式分析了WinForm制作異形窗體與控件的原理、實現(xiàn)步驟與相關操作技巧,需要的朋友可以參考下
    2017-05-05
  • C#程序異常關閉時的捕獲

    C#程序異常關閉時的捕獲

    這篇文章主要為大家詳細介紹了C# Winform程序異常關閉時,進行捕獲并記錄日志,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • C#中的TemplateMethod模式問題分析

    C#中的TemplateMethod模式問題分析

    這篇文章主要介紹了C#中的TemplateMethod模式,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • C#實現(xiàn)簡易計算器小功能

    C#實現(xiàn)簡易計算器小功能

    這篇文章主要為大家詳細介紹了C#實現(xiàn)簡易計算器小功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • c#使用wmi查詢usb設備信息示例

    c#使用wmi查詢usb設備信息示例

    這篇文章主要介紹了c#使用wmi查詢usb設備信息示例,大家參考使用吧
    2014-01-01
  • C#生成帶二維碼的專屬微信公眾號推廣海報實例代碼

    C#生成帶二維碼的專屬微信公眾號推廣海報實例代碼

    這篇文章主要給大家介紹了關于利用C#如何生成帶二維碼的專屬微信公眾號推廣海報的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們一起來看看吧
    2018-12-12
  • C#加密解密類實例程序

    C#加密解密類實例程序

    這篇文章主要介紹了C#加密解密類實例程序,大家參考使用吧
    2013-12-12
  • C# GetField方法的應用實例講解

    C# GetField方法的應用實例講解

    C#中的GetField是一個反射方法,用于獲取指定類型的字段信息,它可以通過字段名稱來獲取字段對象,并且可以在運行時動態(tài)地訪問和操作這些字段,本文給大家介紹了C# GetField方法的應用,需要的朋友可以參考下
    2024-04-04
  • c#實現(xiàn)用SQL池,多線程定時批量執(zhí)行SQL語句的方法

    c#實現(xiàn)用SQL池,多線程定時批量執(zhí)行SQL語句的方法

    構建SQL池,分離業(yè)務邏輯層和數(shù)據(jù)訪問層,讓業(yè)務邏輯層從低效的數(shù)據(jù)庫操作解脫,以提高系統(tǒng)整體性能
    2013-10-10

最新評論