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

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

 更新時(shí)間:2022年04月18日 10:15:27   作者:農(nóng)碼一生  
這篇文章介紹了C#在復(fù)雜多線程環(huán)境下使用讀寫(xiě)鎖同步寫(xiě)入文件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(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ù),迭代寫(xiě)入N個(gè)日志
            SumLogCount += LogCount;
            ThreadPool.QueueUserWorkItem((obj) =>
            {
                Parallel.For(0, LogCount, e =>
                {
                    WriteLog();
                });
            });
            //在新的線程里,添加N個(gè)寫(xiě)入日志的任務(wù)到線程池
            SumLogCount += LogCount;
            var thread1 = new Thread(() =>
            {
                Parallel.For(0, LogCount, e =>
                {
                    ThreadPool.QueueUserWorkItem((subObj) =>
                    {
                        WriteLog();
                    });
                });
            });
            thread1.IsBackground = false;
            thread1.Start();
            //添加N個(gè)寫(xiě)入日志的任務(wù)到線程池
            SumLogCount += LogCount;
            Parallel.For(0, LogCount, e =>
            {
                ThreadPool.QueueUserWorkItem((obj) =>
                {
                    WriteLog();
                });
            });
            //在新的線程里,迭代寫(xiě)入N個(gè)日志
            SumLogCount += LogCount;
            var thread2 = new Thread(() =>
            {
                Parallel.For(0, LogCount, e =>
                {
                    WriteLog();
                });
            });
            thread2.IsBackground = false;
            thread2.Start();
            //在當(dāng)前線程里,迭代寫(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ě)入需要等待本次寫(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í)間持有讀線程鎖或?qū)懢€程鎖會(huì)使其他線程發(fā)生饑餓 (starve)。 為了得到最好的性能,需要考慮重新構(gòu)造應(yīng)用程序以將寫(xiě)訪問(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é)果:

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

代碼二:

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

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

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

                //使用互斥鎖操作寫(xiě)入,由于同一時(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)過(guò)測(cè)試并上線運(yùn)行,可直接使用</remarks>
        public static class MutexExample
        {
            /// <summary>
            /// 進(jìn)程間同步執(zhí)行的簡(jiǎn)單例子
            /// </summary>
            /// <param name="action">同步處理代碼</param>
            /// <param name="mutexKey">操作系統(tǒng)級(jí)的同步鍵
            /// (如果將 name 指定為 null 或空字符串,則創(chuàng)建一個(gè)局部互斥體。 
            /// 如果名稱以前綴“Global\”開(kāi)頭,則 mutex 在所有終端服務(wù)器會(huì)話中均為可見(jiàn)。 
            /// 如果名稱以前綴“Local\”開(kāi)頭,則 mutex 僅在創(chuàng)建它的終端服務(wù)器會(huì)話中可見(jiàn)。 
            /// 如果創(chuàng)建已命名 mutex 時(shí)不指定前綴,則它將采用前綴“Local\”。)</param>
            /// <remarks>不重試且不考慮異常情況處理的簡(jiǎn)單例子</remarks>
            [Obsolete(error: false, message: "請(qǐng)使用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>
            /// 獲取文件名對(duì)應(yīng)的進(jìn)程同步鍵
            /// </summary>
            /// <param name="filePath">文件路徑(請(qǐng)注意大小寫(xiě)及空格)</param>
            /// <returns>進(jìn)程同步鍵(互斥體名稱)</returns>
            public static string GetFilePathMutexKey(string filePath)
            {
                //生成文件對(duì)應(yīng)的同步鍵,可自定義格式(互斥體名稱對(duì)特殊字符支持不友好,遂轉(zhuǎn)換為BASE64格式字符串)
                var fileKey = Convert.ToBase64String(Encoding.Default.GetBytes(string.Format(@"FILE\{0}", filePath)));
                //轉(zhuǎn)換為操作系統(tǒng)級(jí)的同步鍵
                var mutexKey = string.Format(@"Global\{0}", fileKey);
                return mutexKey;
            }

            /// <summary>
            /// 進(jìn)程間同步執(zhí)行
            /// </summary>
            /// <param name="mutexKey">操作系統(tǒng)級(jí)的同步鍵
            /// (如果將 name 指定為 null 或空字符串,則創(chuàng)建一個(gè)局部互斥體。 
            /// 如果名稱以前綴“Global\”開(kāi)頭,則 mutex 在所有終端服務(wù)器會(huì)話中均為可見(jiàn)。 
            /// 如果名稱以前綴“Local\”開(kāi)頭,則 mutex 僅在創(chuàng)建它的終端服務(wù)器會(huì)話中可見(jiàn)。 
            /// 如果創(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)級(jí)的同步鍵
            /// (如果將 name 指定為 null 或空字符串,則創(chuàng)建一個(gè)局部互斥體。 
            /// 如果名稱以前綴“Global\”開(kāi)頭,則 mutex 在所有終端服務(wù)器會(huì)話中均為可見(jiàn)。 
            /// 如果名稱以前綴“Local\”開(kāi)頭,則 mutex 僅在創(chuàng)建它的終端服務(wù)器會(huì)話中可見(jiàn)。 
            /// 如果創(chuàng)建已命名 mutex 時(shí)不指定前綴,則它將采用前綴“Local\”。)</param>
            /// <param name="action">同步處理操作</param>
            /// <param name="recursive">指示當(dāng)前調(diào)用是否為遞歸處理,遞歸處理時(shí)檢測(cè)到異常則拋出異常,避免進(jìn)入無(wú)限遞歸</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í)間過(guò)短,則可能同時(shí)聲明了多個(gè)名稱相同的互斥體,并且同名的多個(gè)互斥體之間并不同步,高并發(fā)用戶請(qǐng)另行處理
                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)程已上鎖且沒(méi)有正常釋放互斥鎖時(shí)(譬如進(jìn)程忽然關(guān)閉或退出),則會(huì)拋出AbandonedMutexException異常
                    catch (AbandonedMutexException ex)
                    {
                        //避免進(jìn)入無(wú)限遞歸
                        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 測(cè)試寫(xiě)文件的代碼
        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)境下使用讀寫(xiě)鎖同步寫(xiě)入文件的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

万州区| 临泉县| 信阳市| 登封市| 读书| 奉新县| 吉林市| 南华县| 林口县| 石门县| 徐汇区| 两当县| 襄樊市| 永仁县| 溧阳市| 兴和县| 仪征市| 张北县| 循化| 饶平县| 株洲县| 奇台县| 惠安县| 冀州市| 开封县| 南澳县| 屯昌县| 洛扎县| 城步| 甘德县| 方山县| 调兵山市| 连平县| 永顺县| 贺州市| 昌宁县| 墨竹工卡县| 彰化市| 来安县| 青海省| 尼木县|