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

C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件

 更新時(shí)間:2022年04月18日 10:15:27   作者:農(nóng)碼一生  
這篇文章介紹了C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

代碼一:

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

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

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

代碼二:

class Program
    {
        static void Main(string[] args)
        {
            #region 簡單使用
            //var mutexKey = MutexExample.GetFilePathMutexKey("文件路徑");
            //MutexExample.MutexExec(mutexKey, () =>
            //{
            //    Console.WriteLine("需要進(jìn)程同步執(zhí)行的代碼");
            //});
            #endregion

            #region 測試代碼
            //D:\Winform\多線程\多線程_互斥信號量\bin\Debug\TEST.LOG
            var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.log").ToUpper();
            var mutexKey = MutexExample.GetFilePathMutexKey(filePath);

            //同時(shí)開啟N個(gè)寫入線程
            Parallel.For(0, LogCount, e =>
            {
                //沒使用互斥鎖操作寫入,大量寫入錯(cuò)誤;FileStream包含F(xiàn)ileShare的構(gòu)造函數(shù)也僅實(shí)現(xiàn)了進(jìn)程內(nèi)的線程同步,多進(jìn)程同時(shí)寫入時(shí)也會(huì)出錯(cuò)
                //WriteLog(filePath);

                //使用互斥鎖操作寫入,由于同一時(shí)間僅有一個(gè)線程操作,所以不會(huì)出錯(cuò)
                MutexExample.MutexExec(mutexKey, () =>
                {
                    WriteLog(filePath);
                });
            });

            Console.WriteLine(string.Format("Log Count:{0}.\t\tWrited Count:{1}.\tFailed Count:{2}.", LogCount.ToString(), WritedCount.ToString(), FailedCount.ToString()));
            Console.Read();
            #endregion
        }


        /// <summary>
        /// C#互斥量使用示例代碼
        /// </summary>
        /// <remarks>已在經(jīng)過測試并上線運(yùn)行,可直接使用</remarks>
        public static class MutexExample
        {
            /// <summary>
            /// 進(jìn)程間同步執(zhí)行的簡單例子
            /// </summary>
            /// <param name="action">同步處理代碼</param>
            /// <param name="mutexKey">操作系統(tǒng)級的同步鍵
            /// (如果將 name 指定為 null 或空字符串,則創(chuàng)建一個(gè)局部互斥體。 
            /// 如果名稱以前綴“Global\”開頭,則 mutex 在所有終端服務(wù)器會(huì)話中均為可見。 
            /// 如果名稱以前綴“Local\”開頭,則 mutex 僅在創(chuàng)建它的終端服務(wù)器會(huì)話中可見。 
            /// 如果創(chuàng)建已命名 mutex 時(shí)不指定前綴,則它將采用前綴“Local\”。)</param>
            /// <remarks>不重試且不考慮異常情況處理的簡單例子</remarks>
            [Obsolete(error: false, message: "請使用MutexExec")]
            public static void MutexExecEasy(string mutexKey, Action action)
            {
                //聲明一個(gè)已命名的互斥體,實(shí)現(xiàn)進(jìn)程間同步;該命名互斥體不存在則自動(dòng)創(chuàng)建,已存在則直接獲取
                using (Mutex mut = new Mutex(false, mutexKey))
                {
                    try
                    {
                        //上鎖,其他線程需等待釋放鎖之后才能執(zhí)行處理;若其他線程已經(jīng)上鎖或優(yōu)先上鎖,則先等待其他線程執(zhí)行完畢
                        mut.WaitOne();
                        //執(zhí)行處理代碼(在調(diào)用WaitHandle.WaitOne至WaitHandle.ReleaseMutex的時(shí)間段里,只有一個(gè)線程處理,其他線程都得等待釋放鎖后才能執(zhí)行該代碼段)
                        action();
                    }
                    finally
                    {
                        //釋放鎖,讓其他進(jìn)程(或線程)得以繼續(xù)執(zhí)行
                        mut.ReleaseMutex();
                    }
                }
            }


            /// <summary>
            /// 獲取文件名對應(yīng)的進(jìn)程同步鍵
            /// </summary>
            /// <param name="filePath">文件路徑(請注意大小寫及空格)</param>
            /// <returns>進(jìn)程同步鍵(互斥體名稱)</returns>
            public static string GetFilePathMutexKey(string filePath)
            {
                //生成文件對應(yīng)的同步鍵,可自定義格式(互斥體名稱對特殊字符支持不友好,遂轉(zhuǎn)換為BASE64格式字符串)
                var fileKey = Convert.ToBase64String(Encoding.Default.GetBytes(string.Format(@"FILE\{0}", filePath)));
                //轉(zhuǎn)換為操作系統(tǒng)級的同步鍵
                var mutexKey = string.Format(@"Global\{0}", fileKey);
                return mutexKey;
            }

            /// <summary>
            /// 進(jìn)程間同步執(zhí)行
            /// </summary>
            /// <param name="mutexKey">操作系統(tǒng)級的同步鍵
            /// (如果將 name 指定為 null 或空字符串,則創(chuàng)建一個(gè)局部互斥體。 
            /// 如果名稱以前綴“Global\”開頭,則 mutex 在所有終端服務(wù)器會(huì)話中均為可見。 
            /// 如果名稱以前綴“Local\”開頭,則 mutex 僅在創(chuàng)建它的終端服務(wù)器會(huì)話中可見。 
            /// 如果創(chuàng)建已命名 mutex 時(shí)不指定前綴,則它將采用前綴“Local\”。)</param>
            /// <param name="action">同步處理操作</param>
            public static void MutexExec(string mutexKey, Action action)
            {
                MutexExec(mutexKey: mutexKey, action: action, recursive: false);
            }

            /// <summary>
            /// 進(jìn)程間同步執(zhí)行
            /// </summary>
            /// <param name="mutexKey">操作系統(tǒng)級的同步鍵
            /// (如果將 name 指定為 null 或空字符串,則創(chuàng)建一個(gè)局部互斥體。 
            /// 如果名稱以前綴“Global\”開頭,則 mutex 在所有終端服務(wù)器會(huì)話中均為可見。 
            /// 如果名稱以前綴“Local\”開頭,則 mutex 僅在創(chuàng)建它的終端服務(wù)器會(huì)話中可見。 
            /// 如果創(chuàng)建已命名 mutex 時(shí)不指定前綴,則它將采用前綴“Local\”。)</param>
            /// <param name="action">同步處理操作</param>
            /// <param name="recursive">指示當(dāng)前調(diào)用是否為遞歸處理,遞歸處理時(shí)檢測到異常則拋出異常,避免進(jìn)入無限遞歸</param>
            private static void MutexExec(string mutexKey, Action action, bool recursive)
            {
                //聲明一個(gè)已命名的互斥體,實(shí)現(xiàn)進(jìn)程間同步;該命名互斥體不存在則自動(dòng)創(chuàng)建,已存在則直接獲取
                //initiallyOwned: false:默認(rèn)當(dāng)前線程并不擁有已存在互斥體的所屬權(quán),即默認(rèn)本線程并非為首次創(chuàng)建該命名互斥體的線程
                //注意:并發(fā)聲明同名的命名互斥體時(shí),若間隔時(shí)間過短,則可能同時(shí)聲明了多個(gè)名稱相同的互斥體,并且同名的多個(gè)互斥體之間并不同步,高并發(fā)用戶請另行處理
                using (Mutex mut = new Mutex(initiallyOwned: false, name: mutexKey))
                {
                    try
                    {
                        //上鎖,其他線程需等待釋放鎖之后才能執(zhí)行處理;若其他線程已經(jīng)上鎖或優(yōu)先上鎖,則先等待其他線程執(zhí)行完畢
                        mut.WaitOne();
                        //執(zhí)行處理代碼(在調(diào)用WaitHandle.WaitOne至WaitHandle.ReleaseMutex的時(shí)間段里,只有一個(gè)線程處理,其他線程都得等待釋放鎖后才能執(zhí)行該代碼段)
                        action();
                    }
                    //當(dāng)其他進(jìn)程已上鎖且沒有正常釋放互斥鎖時(shí)(譬如進(jìn)程忽然關(guān)閉或退出),則會(huì)拋出AbandonedMutexException異常
                    catch (AbandonedMutexException ex)
                    {
                        //避免進(jìn)入無限遞歸
                        if (recursive)
                            throw ex;

                        //非遞歸調(diào)用,由其他進(jìn)程拋出互斥鎖解鎖異常時(shí),重試執(zhí)行
                        MutexExec(mutexKey: mutexKey, action: action, recursive: true);
                    }
                    finally
                    {
                        //釋放鎖,讓其他進(jìn)程(或線程)得以繼續(xù)執(zhí)行
                        mut.ReleaseMutex();
                    }
                }
            }
        }


        #region 測試寫文件的代碼
        static int LogCount = 500;
        static int WritedCount = 0;
        static int FailedCount = 0;
        static void WriteLog(string logFilePath)
        {
            try
            {
                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)
            {
                Console.WriteLine(ex.Message);
                FailedCount++;
            }
        }
        #endregion
    }

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

到此這篇關(guān)于C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#使用checkedListBox1控件鏈接數(shù)據(jù)庫的方法示例

    C#使用checkedListBox1控件鏈接數(shù)據(jù)庫的方法示例

    這篇文章主要介紹了C#使用checkedListBox1控件鏈接數(shù)據(jù)庫的方法,結(jié)合具體實(shí)例形式分析了數(shù)據(jù)庫的創(chuàng)建及checkedListBox1控件連接數(shù)據(jù)庫的相關(guān)操作技巧,需要的朋友可以參考下
    2017-06-06
  • 用?FieldMask?提高?C#?gRpc?的服務(wù)性能

    用?FieldMask?提高?C#?gRpc?的服務(wù)性能

    這篇文章主要介紹了用?FieldMask?提高?C#?gRpc?的服務(wù)性能,FieldMask?是一個(gè)?protobuf?消息,包含一個(gè)名為?paths?的字段,用于指定用于指定讀取操作返回或更新操作修改的字,下文詳細(xì)內(nèi)容,需要的朋友可以參考一下
    2022-03-03
  • Url相對路徑的問題總結(jié)

    Url相對路徑的問題總結(jié)

    很多時(shí)候,我們在圖片或者其他(a標(biāo)簽,flash)中指定鏈接的時(shí)候,我們需要選擇是使用絕對路徑,或者是相對路徑.
    2012-11-11
  • npoi2.0將datatable對象轉(zhuǎn)換為excel2007示例

    npoi2.0將datatable對象轉(zhuǎn)換為excel2007示例

    這篇文章主要介紹了npoi2.0將datatable對象轉(zhuǎn)換為excel2007示例的相關(guān)資料
    2014-04-04
  • 自定義時(shí)間格式轉(zhuǎn)換代碼分享

    自定義時(shí)間格式轉(zhuǎn)換代碼分享

    自定義時(shí)間格式轉(zhuǎn)換,如"2012年5月14日"的日期字符串,大家參考使用吧
    2013-12-12
  • 一篇文章教會(huì)你用Unity制作網(wǎng)格地圖生成組件

    一篇文章教會(huì)你用Unity制作網(wǎng)格地圖生成組件

    網(wǎng)格地圖這個(gè)功能在策略型游戲中應(yīng)用比較廣泛,基本情況下會(huì)將地圖分割成正方形網(wǎng)格或者六邊形網(wǎng)格,這篇文章主要給大家介紹了如何通過一篇文章學(xué)會(huì)用Unity制作網(wǎng)格地圖生成組件的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • UGUI繪制動(dòng)態(tài)曲線

    UGUI繪制動(dòng)態(tài)曲線

    這篇文章主要為大家詳細(xì)介紹了UGUI繪制動(dòng)態(tài)曲線的具體方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 詳解c# 協(xié)變和逆變

    詳解c# 協(xié)變和逆變

    這篇文章主要介紹了c# 協(xié)變和逆變的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c#,感興趣的朋友可以了解下
    2020-11-11
  • C#解決SQlite并發(fā)異常問題的方法(使用讀寫鎖)

    C#解決SQlite并發(fā)異常問題的方法(使用讀寫鎖)

    這篇文章主要介紹了C#解決SQlite并發(fā)異常問題的方法,通過使用讀寫鎖達(dá)到多線程安全訪問,進(jìn)而解決SQLite并發(fā)異常的問題,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-07-07
  • C#實(shí)現(xiàn)十五子游戲

    C#實(shí)現(xiàn)十五子游戲

    這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)十五子游戲的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05

最新評論