最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#使用讀寫(xiě)鎖三行代碼簡(jiǎn)單解決多線(xiàn)程并發(fā)的問(wèn)題

 更新時(shí)間:2016年12月12日 09:43:51   作者:弎吩鍾熱℃  
本文主要介紹了C#使用讀寫(xiě)鎖三行代碼簡(jiǎn)單解決多線(xiàn)程并發(fā)寫(xiě)入文件時(shí)提示“文件正在由另一進(jìn)程使用,因此該進(jìn)程無(wú)法訪(fǎng)問(wèn)此文件”的問(wèn)題。需要的朋友可以參考借鑒

在開(kāi)發(fā)程序的過(guò)程中,難免少不了寫(xiě)入錯(cuò)誤日志這個(gè)關(guān)鍵功能。實(shí)現(xiàn)這個(gè)功能,可以選擇使用第三方日志插件,也可以選擇使用數(shù)據(jù)庫(kù),還可以自己寫(xiě)個(gè)簡(jiǎn)單的方法把錯(cuò)誤信息記錄到日志文件。

選擇最后一種方法實(shí)現(xiàn)的時(shí)候,若對(duì)文件操作與線(xiàn)程同步不熟悉,問(wèn)題就有可能出現(xiàn)了,因?yàn)橥粋€(gè)文件并不允許多個(gè)線(xiàn)程同時(shí)寫(xiě)入,否則會(huì)提示“文件正在由另一進(jìn)程使用,因此該進(jìn)程無(wú)法訪(fǎng)問(wèn)此文件”。

這是文件的并發(fā)寫(xiě)入問(wèn)題,就需要用到線(xiàn)程同步。而微軟也給線(xiàn)程同步提供了一些相關(guān)的類(lèi)可以達(dá)到這樣的目的,本文使用到的 System.Threading.ReaderWriterLockSlim 便是其中之一。

該類(lèi)用于管理資源訪(fǎng)問(wèn)的鎖定狀態(tài),可實(shí)現(xiàn)多線(xiàn)程讀取或進(jìn)行獨(dú)占式寫(xiě)入訪(fǎng)問(wèn)。利用這個(gè)類(lèi),我們就可以避免在同一時(shí)間段內(nèi)多線(xiàn)程同時(shí)寫(xiě)入一個(gè)文件而導(dǎo)致的并發(fā)寫(xiě)入問(wèn)題。

讀寫(xiě)鎖是以 ReaderWriterLockSlim 對(duì)象作為鎖管理資源的,不同的 ReaderWriterLockSlim 對(duì)象中鎖定同一個(gè)文件也會(huì)被視為不同的鎖進(jìn)行管理,這種差異可能會(huì)再次導(dǎo)致文件的并發(fā)寫(xiě)入問(wèn)題,所以 ReaderWriterLockSlim 應(yīng)盡量定義為只讀的靜態(tài)對(duì)象。

ReaderWriterLockSlim 有幾個(gè)關(guān)鍵的方法,本文僅討論寫(xiě)入鎖:

調(diào)用 EnterWriteLock 方法 進(jìn)入寫(xiě)入狀態(tài),在調(diào)用線(xiàn)程進(jìn)入鎖定狀態(tài)之前一直處于阻塞狀態(tài),因此可能永遠(yuǎn)都不返回。

調(diào)用 TryEnterWriteLock 方法 進(jìn)入寫(xiě)入狀態(tài),可指定阻塞的間隔時(shí)間,如果調(diào)用線(xiàn)程在此間隔期間并未進(jìn)入寫(xiě)入模式,將返回false。

調(diào)用 ExitWriteLock 方法 退出寫(xiě)入狀態(tài),應(yīng)使用 finally 塊執(zhí)行 ExitWriteLock 方法,從而確保調(diào)用方退出寫(xiě)入模式。

Don't talk, show me the code.

1.多線(xiàn)程同時(shí)寫(xiě)入文件

class Program
 {
 static int LogCount = 100;
 static int WritedCount = 0;
 static int FailedCount = 0;
 static void Main(string[] args)
 {
 //迭代運(yùn)行寫(xiě)入日志記錄,由于多個(gè)線(xiàn)程同時(shí)寫(xiě)入同一個(gè)文件將會(huì)導(dǎo)致錯(cuò)誤
 Parallel.For(0, LogCount, e =>
 {
 WriteLog();
 });
 Console.WriteLine(string.Format("\r\nLog Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
 Console.Read();
 }
 static void WriteLog()
 {
 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);
 }
 }
 }

運(yùn)行結(jié)果:

不使用讀寫(xiě)鎖,只有部分日志成功寫(xiě)入了日志文件。

2.多線(xiàn)程使用讀寫(xiě)鎖同步寫(xiě)入文件

class Program
 {
 static int LogCount = 100;
 static int WritedCount = 0;
 static int FailedCount = 0;
 static void Main(string[] args)
 {
 //迭代運(yùn)行寫(xiě)入日志記錄
 Parallel.For(0, LogCount, e =>
 {
 WriteLog();
 });
 Console.WriteLine(string.Format("\r\nLog Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
 Console.Read();
 }
 //讀寫(xiě)鎖,當(dāng)資源處于寫(xiě)入模式時(shí),其他線(xiàn)程寫(xiě)入需要等待本次寫(xiě)入結(jié)束之后才能繼續(xù)寫(xiě)入
 static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
 static void WriteLog()
 {
 try
 {
 //設(shè)置讀寫(xiě)鎖為寫(xiě)入模式獨(dú)占資源,其他寫(xiě)入請(qǐng)求需要等待本次寫(xiě)入結(jié)束之后才能繼續(xù)寫(xiě)入
 //注意:長(zhǎng)時(shí)間持有讀線(xiàn)程鎖或?qū)懢€(xiàn)程鎖會(huì)使其他線(xiàn)程發(fā)生饑餓 (starve)。 為了得到最好的性能,需要考慮重新構(gòu)造應(yīng)用程序以將寫(xiě)訪(fǎng)問(wèn)的持續(xù)時(shí)間減少到最小。
 // 從性能方面考慮,請(qǐng)求進(jìn)入寫(xiě)入模式應(yīng)該緊跟文件操作之前,在此處進(jìn)入寫(xiě)入模式僅是為了降低代碼復(fù)雜度
 // 因進(jìn)入與退出寫(xiě)入模式應(yīng)在同一個(gè)try finally語(yǔ)句塊內(nèi),所以在請(qǐng)求進(jìn)入寫(xiě)入模式之前不能觸發(fā)異常,否則釋放次數(shù)大于請(qǐng)求次數(shù)將會(huì)觸發(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
 {
 //退出寫(xiě)入模式,釋放資源占用
 //注意:一次請(qǐng)求對(duì)應(yīng)一次釋放
 // 若釋放次數(shù)大于請(qǐng)求次數(shù)將會(huì)觸發(fā)異常[寫(xiě)入鎖定未經(jīng)保持即被釋放]
 // 若請(qǐng)求處理完成后未釋放將會(huì)觸發(fā)異常[此模式不下允許以遞歸方式獲取寫(xiě)入鎖定]
 LogWriteLock.ExitWriteLock();
 }
 }
 }

運(yùn)行結(jié)果:

使用讀寫(xiě)鎖,全部日志成功寫(xiě)入了日志文件。

3.測(cè)試復(fù)雜多線(xiàn)程環(huán)境下使用讀寫(xiě)鎖同步寫(xiě)入文件

 class Program
 {
 static int LogCount = 1000;
 static int SumLogCount = 0;
 static int WritedCount = 0;
 static int FailedCount = 0;
 static void Main(string[] args)
 {
 //往線(xiàn)程池里添加一個(gè)任務(wù),迭代寫(xiě)入N個(gè)日志
 SumLogCount += LogCount;
 ThreadPool.QueueUserWorkItem((obj) =>
 {
 Parallel.For(0, LogCount, e =>
 {
 WriteLog();
 });
 });
 //在新的線(xiàn)程里,添加N個(gè)寫(xiě)入日志的任務(wù)到線(xiàn)程池
 SumLogCount += LogCount;
 var thread1 = new Thread(() =>
 {
 Parallel.For(0, LogCount, e =>
 {
 ThreadPool.QueueUserWorkItem((subObj) =>
 {
 WriteLog();
 });
 });
 });
 thread1.IsBackground = false;
 thread1.Start();
 //添加N個(gè)寫(xiě)入日志的任務(wù)到線(xiàn)程池
 SumLogCount += LogCount;
 Parallel.For(0, LogCount, e =>
 {
 ThreadPool.QueueUserWorkItem((obj) =>
 {
 WriteLog();
 });
 });
 //在新的線(xiàn)程里,迭代寫(xiě)入N個(gè)日志
 SumLogCount += LogCount;
 var thread2 = new Thread(() =>
 {
 Parallel.For(0, LogCount, e =>
 {
 WriteLog();
 });
 });
 thread2.IsBackground = false;
 thread2.Start();
 //在當(dāng)前線(xiàn)程里,迭代寫(xiě)入N個(gè)日志
 SumLogCount += LogCount;
 Parallel.For(0, LogCount, e =>
 {
 WriteLog();
 });
 Console.WriteLine("Main Thread Processed.\r\n");
 while (true)
 {
 Console.WriteLine(string.Format("Sum Log Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", SumLogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
 Console.ReadLine();
 }
 }
 //讀寫(xiě)鎖,當(dāng)資源處于寫(xiě)入模式時(shí),其他線(xiàn)程寫(xiě)入需要等待本次寫(xiě)入結(jié)束之后才能繼續(xù)寫(xiě)入
 static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
 static void WriteLog()
 {
 try
 {
 //設(shè)置讀寫(xiě)鎖為寫(xiě)入模式獨(dú)占資源,其他寫(xiě)入請(qǐng)求需要等待本次寫(xiě)入結(jié)束之后才能繼續(xù)寫(xiě)入
 //注意:長(zhǎng)時(shí)間持有讀線(xiàn)程鎖或?qū)懢€(xiàn)程鎖會(huì)使其他線(xiàn)程發(fā)生饑餓 (starve)。 為了得到最好的性能,需要考慮重新構(gòu)造應(yīng)用程序以將寫(xiě)訪(fǎng)問(wèn)的持續(xù)時(shí)間減少到最小。
 // 從性能方面考慮,請(qǐng)求進(jìn)入寫(xiě)入模式應(yīng)該緊跟文件操作之前,在此處進(jìn)入寫(xiě)入模式僅是為了降低代碼復(fù)雜度
 // 因進(jìn)入與退出寫(xiě)入模式應(yīng)在同一個(gè)try finally語(yǔ)句塊內(nèi),所以在請(qǐng)求進(jìn)入寫(xiě)入模式之前不能觸發(fā)異常,否則釋放次數(shù)大于請(qǐng)求次數(shù)將會(huì)觸發(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
 {
 //退出寫(xiě)入模式,釋放資源占用
 //注意:一次請(qǐng)求對(duì)應(yīng)一次釋放
 // 若釋放次數(shù)大于請(qǐng)求次數(shù)將會(huì)觸發(fā)異常[寫(xiě)入鎖定未經(jīng)保持即被釋放]
 // 若請(qǐng)求處理完成后未釋放將會(huì)觸發(fā)異常[此模式不下允許以遞歸方式獲取寫(xiě)入鎖定]
 LogWriteLock.ExitWriteLock();
 }
 }
 }

運(yùn)行結(jié)果:

部分日志文件內(nèi)容:

 ...
Tid: 36 2016年12月11日 15:29:22.825
Tid: 29 2016年12月11日 15:29:22.830
Tid: 6 2016年12月11日 15:29:22.838
Tid: 26 2016年12月11日 15:29:22.845
Tid: 34 2016年12月11日 15:29:22.854
Tid: 24 2016年12月11日 15:29:22.863
Tid: 27 2016年12月11日 15:29:22.872
Tid: 14 2016年12月11日 15:29:22.877
Tid: 23 2016年12月11日 15:29:22.886
Tid: 20 2016年12月11日 15:29:22.892
Tid: 30 2016年12月11日 15:29:22.898
Tid: 9 2016年12月11日 15:29:22.904
Tid: 21 2016年12月11日 15:29:22.909
Tid: 22 2016年12月11日 15:29:22.915
Tid: 7 2016年12月11日 15:29:22.920
Tid: 3 2016年12月11日 15:29:22.925
Tid: 12 2016年12月11日 15:29:22.931
Tid: 5 2016年12月11日 15:29:22.937
Tid: 13 2016年12月11日 15:29:22.942
Tid: 11 2016年12月11日 15:29:22.947
Tid: 19 2016年12月11日 15:29:22.953
Tid: 37 2016年12月11日 15:29:22.958
Tid: 37 2016年12月11日 15:29:22.964
Tid: 40 2016年12月11日 15:29:22.970
Tid: 40 2016年12月11日 15:29:22.975
Tid: 40 2016年12月11日 15:29:22.980
Tid: 40 2016年12月11日 15:29:22.985
Tid: 40 2016年12月11日 15:29:22.991
Tid: 40 2016年12月11日 15:29:22.997
Tid: 31 2016年12月11日 15:29:23.3
Tid: 31 2016年12月11日 15:29:23.9
Tid: 31 2016年12月11日 15:29:23.14
Tid: 31 2016年12月11日 15:29:23.20
Tid: 31 2016年12月11日 15:29:23.27
Tid: 31 2016年12月11日 15:29:23.33
Tid: 31 2016年12月11日 15:29:23.38
Tid: 31 2016年12月11日 15:29:23.44
Tid: 31 2016年12月11日 15:29:23.49
Tid: 31 2016年12月11日 15:29:23.57
Tid: 31 2016年12月11日 15:29:23.63
Tid: 31 2016年12月11日 15:29:23.68
Tid: 31 2016年12月11日 15:29:23.74
Tid: 16 2016年12月11日 15:29:23.80
Tid: 16 2016年12月11日 15:29:23.86
Tid: 16 2016年12月11日 15:29:23.93
Tid: 16 2016年12月11日 15:29:23.99
Tid: 16 2016年12月11日 15:29:23.105
Tid: 16 2016年12月11日 15:29:23.110
Tid: 16 2016年12月11日 15:29:23.116
Tid: 38 2016年12月11日 15:29:23.122
Tid: 38 2016年12月11日 15:29:23.128
Tid: 28 2016年12月11日 15:29:23.134
Tid: 19 2016年12月11日 15:29:23.139
Tid: 25 2016年12月11日 15:29:23.146
Tid: 37 2016年12月11日 15:29:23.152
Tid: 39 2016年12月11日 15:29:23.158
Tid: 32 2016年12月11日 15:29:23.164
Tid: 33 2016年12月11日 15:29:23.170
Tid: 31 2016年12月11日 15:29:23.176
Tid: 35 2016年12月11日 15:29:23.182
Tid: 40 2016年12月11日 15:29:23.189
Tid: 15 2016年12月11日 15:29:23.194
Tid: 18 2016年12月11日 15:29:23.202
Tid: 17 2016年12月11日 15:29:23.208
Tid: 10 2016年12月11日 15:29:23.215
Tid: 16 2016年12月11日 15:29:23.221

復(fù)雜多線(xiàn)程環(huán)境下使用讀寫(xiě)鎖,全部日志成功寫(xiě)入了日志文件,由ThreadId和DateTime可以看出是由不同的線(xiàn)程同步寫(xiě)入。

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • 關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案

    關(guān)于ASP網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案

    asp網(wǎng)頁(yè)實(shí)際上就是動(dòng)態(tài)網(wǎng)頁(yè),是在服務(wù)端執(zhí)行和解析的。有時(shí)也很奇怪,經(jīng)常遇到asp網(wǎng)頁(yè)無(wú)法打開(kāi)的情況,下面小編給大家整理些關(guān)于asp網(wǎng)頁(yè)無(wú)法打開(kāi)的解決方案,需要的朋友可以參考下
    2015-08-08
  • C#模擬鏈表數(shù)據(jù)結(jié)構(gòu)的實(shí)例解析

    C#模擬鏈表數(shù)據(jù)結(jié)構(gòu)的實(shí)例解析

    這篇文章主要介紹了C#模擬鏈表數(shù)據(jù)結(jié)構(gòu)的實(shí)例解析,包括隊(duì)雙向鏈表的模擬方法,例子中隊(duì)鏈表的操作也有很好的說(shuō)明,需要的朋友可以參考下
    2016-04-04
  • c#判斷正確的ip地址格式示例

    c#判斷正確的ip地址格式示例

    這篇文章主要介紹了c#判斷正確的ip地址格式示例,需要的朋友可以參考下
    2014-02-02
  • C#將PDF轉(zhuǎn)為多種圖像文件格式的方法(Png/Bmp/Emf/Tiff)

    C#將PDF轉(zhuǎn)為多種圖像文件格式的方法(Png/Bmp/Emf/Tiff)

    這里介紹將PDF轉(zhuǎn)換多種不同格式的圖像文件格式,如PNG,BMP,EMF,TIFF等,同時(shí),轉(zhuǎn)換文檔也分為轉(zhuǎn)換全部文檔和轉(zhuǎn)換部分文檔為圖片兩種情況,本文也將作進(jìn)一步介紹
    2018-02-02
  • 基于C#實(shí)現(xiàn)磁性吸附窗體

    基于C#實(shí)現(xiàn)磁性吸附窗體

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)磁性吸附窗體,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#中IEnumerable、ICollection、IList、List之間的區(qū)別

    C#中IEnumerable、ICollection、IList、List之間的區(qū)別

    IEnumerable、ICollection、IList、List之間的區(qū)別,本文分別分析了它的實(shí)現(xiàn)源碼,從而總結(jié)出了它們之間的關(guān)系和不同之處。對(duì)C# IEnumerable、ICollection、IList、List相關(guān)知識(shí),感興趣的朋友一起看看吧
    2021-07-07
  • C# wpf簡(jiǎn)單顏色板的實(shí)現(xiàn)

    C# wpf簡(jiǎn)單顏色板的實(shí)現(xiàn)

    wpf本身沒(méi)有提供顏色板之類(lèi)的控件,有些業(yè)務(wù)使用場(chǎng)景需要使用顏色板之類(lèi)的控件,本文就簡(jiǎn)單實(shí)現(xiàn),感興趣的可以了解一下
    2021-10-10
  • c# WPF中System.Windows.Interactivity的使用

    c# WPF中System.Windows.Interactivity的使用

    這篇文章主要介紹了c# WPF中System.Windows.Interactivity的使用,幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下
    2021-03-03
  • 【C#基礎(chǔ)】Substring截取字符串的方法小結(jié)(推薦)

    【C#基礎(chǔ)】Substring截取字符串的方法小結(jié)(推薦)

    這篇文章主要介紹了Substring截取字符串方法小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • DataGridView清除顯示的數(shù)據(jù)、設(shè)定右鍵菜單

    DataGridView清除顯示的數(shù)據(jù)、設(shè)定右鍵菜單

    這篇文章介紹了DataGridView清除顯示的數(shù)據(jù)、設(shè)定右鍵菜單的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-02-02

最新評(píng)論

安西县| 陵川县| 昔阳县| 柳江县| 綦江县| 台北市| 贡觉县| 武胜县| 灵川县| 西峡县| 密山市| 彩票| 卓尼县| 普宁市| 拉孜县| 永城市| 河间市| 广平县| 县级市| 铁岭市| 柏乡县| 浦县| 乐平市| 台中县| 澜沧| 金秀| 汉寿县| 天祝| 萍乡市| 阆中市| 安泽县| 萨嘎县| 互助| 连城县| 天柱县| 信宜市| 娱乐| 平阳县| 沁阳市| 长寿区| 天气|