C# 實(shí)現(xiàn)多線(xiàn)程啟動(dòng)停止暫停繼續(xù)
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
前言多線(xiàn)程編程是提升應(yīng)用程序性能和響應(yīng)能力的關(guān)鍵技術(shù)之一。C# 提供了強(qiáng)大的多線(xiàn)程支持,能夠輕松創(chuàng)建并發(fā)任務(wù),優(yōu)化資源利用,并改善用戶(hù)體驗(yàn)。然而,實(shí)現(xiàn)多線(xiàn)程的同時(shí),如何安全有效地管理這些線(xiàn)程(如啟動(dòng)、停止、暫停和繼續(xù))是一個(gè)重要的問(wèn)題。 大部分初學(xué)者在學(xué)習(xí)C#上位機(jī)編程時(shí),多線(xiàn)程是一個(gè)很難逾越的鴻溝,不合理地使用多線(xiàn)程,會(huì)導(dǎo)致經(jīng)常出現(xiàn)各種奇怪的問(wèn)題,這也是很多初學(xué)者不敢使用多線(xiàn)程的原因。但是在實(shí)際開(kāi)發(fā)中,多線(xiàn)程是一個(gè)不可避免的技術(shù)棧,基本上每個(gè)項(xiàng)目都會(huì)使用到,因此學(xué)好多線(xiàn)程技術(shù),很重要。 本文將深入探討如何使用 C# 實(shí)現(xiàn)多線(xiàn)程的啟動(dòng)、停止、暫停和繼續(xù)功能。我們將介紹相關(guān)的理論基礎(chǔ),分享實(shí)用代碼示例,并討論最佳實(shí)踐和常見(jiàn)問(wèn)題的解決方案。 多線(xiàn)程原理 什么是多線(xiàn)程? 多線(xiàn)程是一種編程技術(shù),允許一個(gè)程序同時(shí)運(yùn)行多個(gè)獨(dú)立的執(zhí)行流程,每個(gè)執(zhí)行流程稱(chēng)為一個(gè)線(xiàn)程。通過(guò)這種方式,程序可以提高并發(fā)性和效率,更有效地利用系統(tǒng)資源。 單核CPU與多線(xiàn)程 想象一下創(chuàng)業(yè)初期的情景:你可能需要身兼多職,既要處理業(yè)務(wù),又要負(fù)責(zé)技術(shù)支持,還要管理財(cái)務(wù)。雖然你看似在“同時(shí)”完成這些任務(wù),但實(shí)際上你是通過(guò)高效的時(shí)間管理來(lái)快速切換不同職責(zé),從而營(yíng)造出多任務(wù)并行的假象。 這正是單核CPU實(shí)現(xiàn)多線(xiàn)程的方式——通過(guò)時(shí)間片輪轉(zhuǎn)(Time-Slicing)機(jī)制,CPU在極短的時(shí)間間隔內(nèi)(通常為10-100毫秒)快速切換不同的線(xiàn)程,使得用戶(hù)感覺(jué)所有任務(wù)都在同時(shí)進(jìn)行。 多核CPU與多線(xiàn)程 隨著計(jì)算機(jī)技術(shù)的進(jìn)步,現(xiàn)代CPU大多具備多個(gè)核心(如8核、16核等),每個(gè)核心都可以獨(dú)立執(zhí)行任務(wù)。這種多核架構(gòu)真正實(shí)現(xiàn)了多線(xiàn)程的優(yōu)勢(shì):多個(gè)線(xiàn)程可以在不同的核心上同時(shí)運(yùn)行,從而使多段邏輯能夠并行處理。 充分利用多核CPU的多線(xiàn)程能力,不僅可以顯著提升應(yīng)用程序的性能,還能最大限度地發(fā)揮硬件潛力。如果不使用多線(xiàn)程,就如同擁有一輛高性能跑車(chē)卻只用于日常代步,未能充分發(fā)揮其優(yōu)勢(shì)。 多線(xiàn)程發(fā)展 多線(xiàn)程的重要性與挑戰(zhàn) 盡管多線(xiàn)程技術(shù)能夠顯著提升代碼的執(zhí)行效率和CPU資源利用率,許多開(kāi)發(fā)者仍然對(duì)其望而卻步。主要原因在于,如果使用不當(dāng),多線(xiàn)程可能會(huì)引發(fā)各種難以調(diào)試的問(wèn)題,如競(jìng)態(tài)條件、死鎖和數(shù)據(jù)不一致等。 理解多線(xiàn)程的本質(zhì) 重要的是要認(rèn)識(shí)到,多線(xiàn)程本質(zhì)上是"不可控"的。不應(yīng)將其視為簡(jiǎn)單的開(kāi)關(guān)機(jī)制——需要時(shí)開(kāi)啟,不需要時(shí)關(guān)閉。實(shí)際上,多線(xiàn)程的執(zhí)行依賴(lài)于CPU調(diào)度器的決定。 當(dāng)我們說(shuō)"啟動(dòng)多線(xiàn)程"時(shí),實(shí)際上是告訴操作系統(tǒng)這個(gè)線(xiàn)程可以運(yùn)行了,但具體何時(shí)開(kāi)始或停止,則由CPU根據(jù)當(dāng)前系統(tǒng)狀態(tài)來(lái)決定。因此,開(kāi)發(fā)人員只能通過(guò)間接的方式控制線(xiàn)程的行為。 .NET 框架中的多線(xiàn)程演進(jìn) 微軟在多線(xiàn)程支持方面不斷進(jìn)步,.NET 框架也經(jīng)歷了多個(gè)版本的迭代: .NET 1.0:引入了 Thread 類(lèi),提供了基本的多線(xiàn)程支持。 .NET 2.0:推出了 ThreadPool 線(xiàn)程池,提高了線(xiàn)程管理和資源利用的效率。 .NET 3.0:引入了 Task 類(lèi),簡(jiǎn)化了并發(fā)任務(wù)的管理,并逐漸成為多線(xiàn)程編程的最佳實(shí)踐。 .NET 4.0:增加了 Parallel 類(lèi)庫(kù),支持并行編程,進(jìn)一步提升了復(fù)雜任務(wù)處理的能力。 .NET 4.5:引入了 async/await 關(guān)鍵字,使得異步編程更加簡(jiǎn)潔直觀,極大地方便了編寫(xiě)非阻塞代碼。 控制多線(xiàn)程的方法 .NET 框架提供的接口(方法)允許開(kāi)發(fā)人員間接地控制多線(xiàn)程的啟動(dòng)、停止、暫停和繼續(xù)。這些工具不僅簡(jiǎn)化了多線(xiàn)程編程,還提高了代碼的安全性和可靠性。 例如: 啟動(dòng)線(xiàn)程:使用 Thread.Start() 或 Task.Run() 來(lái)啟動(dòng)新線(xiàn)程或任務(wù)。 停止線(xiàn)程:通過(guò)設(shè)置取消標(biāo)記或使用 CancellationToken 安全終止線(xiàn)程。 暫停與繼續(xù)線(xiàn)程:利用信號(hào)量、事件等待句柄 (EventWaitHandle) 和其他同步原語(yǔ)實(shí)現(xiàn)線(xiàn)程的暫停和恢復(fù)。 多線(xiàn)程啟停 Task 類(lèi)是 .NET 中用于處理多線(xiàn)程和異步操作的核心類(lèi)之一,提供了豐富的 API 函數(shù),使得多線(xiàn)程管理變得更加簡(jiǎn)單和直觀。Task 支持多種啟動(dòng)方式,如 Task.Run、Task.Factory.StartNew 和 Start 等。 下面將以 Task.Run 為例,演示如何使用多線(xiàn)程實(shí)現(xiàn)一個(gè)簡(jiǎn)單的案例。 創(chuàng)建一個(gè)簡(jiǎn)單的程序,其中包含一個(gè)值類(lèi)型的變量,該變量每間隔 100 毫秒自增一次,當(dāng)達(dá)到某個(gè)設(shè)定值后重新從零開(kāi)始計(jì)數(shù),并將當(dāng)前值顯示在界面上。這個(gè)例子展示了如何在后臺(tái)線(xiàn)程中執(zhí)行重復(fù)任務(wù),并安全地更新 UI 線(xiàn)程上的控件。 ![]() 所以該任務(wù)執(zhí)行代碼如下: ![]() 我們可以看到在方法里調(diào)用了一個(gè)cts對(duì)象,這個(gè)對(duì)象就是CancellationTokenSource的對(duì)象,因此我們需要?jiǎng)?chuàng)建一個(gè)CancellationTokenSource對(duì)象cts,同時(shí)在屬性CurrentValue中,要顯示控件的值,這里需要用到委托實(shí)現(xiàn)跨線(xiàn)程訪(fǎng)問(wèn)的問(wèn)題,這個(gè)我們后續(xù)專(zhuān)題講解,代碼如下: ![]() 然后在啟動(dòng)線(xiàn)程按鈕的事件里,編寫(xiě)代碼如下: ![]() 停止線(xiàn)程按鈕的事件里,只需要調(diào)用cts的Cancel方法即可: ![]() 我們可以看到,這里就是通過(guò)cts來(lái)控制cts的IsCancellationRequested屬性,進(jìn)而實(shí)現(xiàn)多線(xiàn)程的控制,這里的cts.IsCancellationRequested類(lèi)似于一個(gè)布爾類(lèi)型的標(biāo)志位,但是CancellationTokenSource的作用不僅如此,還可以在此基礎(chǔ)上實(shí)現(xiàn)多線(xiàn)程超時(shí)判斷,注冊(cè)事件等更復(fù)雜的多線(xiàn)程操作。 多線(xiàn)程暫停繼續(xù) 多線(xiàn)程的暫停繼續(xù),.NET為我們提供了另外一個(gè)對(duì)象——ManualResetEvent,這個(gè)對(duì)象會(huì)有一個(gè)值,這個(gè)值是布爾類(lèi)型,就像一個(gè)門(mén)閘一樣,True是打開(kāi)門(mén)閘,F(xiàn)alse是關(guān)閉門(mén)閘,所以想要暫停多線(xiàn)程就調(diào)用這個(gè)對(duì)象的Reset方法,想要繼續(xù)多線(xiàn)程就調(diào)用這個(gè)對(duì)象的Set方法,使用非常簡(jiǎn)單。首先我們創(chuàng)建一下這個(gè)對(duì)象,可以通過(guò)構(gòu)造方法,給這個(gè)對(duì)象賦初始值,我這里為T(mén)rue,這樣就能直接運(yùn)行,不會(huì)阻塞,代碼如下: ![]() 但是如果希望這個(gè)對(duì)象與多線(xiàn)程有所聯(lián)系,必須要在多線(xiàn)程的方法里體現(xiàn)這個(gè)對(duì)象的作用,這個(gè)是調(diào)用這個(gè)對(duì)象的WaitOne方法,表示在調(diào)用的地方阻塞住,通過(guò)判斷True或者False來(lái)決定是否繼續(xù)執(zhí)行,就像大家開(kāi)車(chē)過(guò)高速收費(fèi)站一樣,即使現(xiàn)在普遍采用ETC了,在入口也需要減速,有一個(gè)ETC識(shí)別的過(guò)程,識(shí)別成功才會(huì)抬桿,識(shí)別不對(duì),桿子是不會(huì)自動(dòng)抬起的,這個(gè)是一樣的道理。所以線(xiàn)程執(zhí)行代碼修改如下: ![]() 對(duì)比一下,其實(shí)就是加了一個(gè)manual.WaitOne()。線(xiàn)程暫停繼續(xù)代碼如下: ![]() 暫停繼續(xù)的使用除了ManualResetEvent,還有一個(gè)AutoResetEvent,AutoResetEvent和ManualResetEvent的用法基本上是一樣的,這里就不過(guò)多贅述,大家可以自己嘗試一下。 這兩者的區(qū)別在于一個(gè)是手動(dòng),一個(gè)是自動(dòng),AutoResetEvent會(huì)在置位之后自動(dòng)復(fù)位,這樣體現(xiàn)在多線(xiàn)程里,就是會(huì)只執(zhí)行一次,就像大家進(jìn)小區(qū)一樣,如果有10輛車(chē)在排隊(duì),這時(shí)候如果自動(dòng)模式,每次都要抬桿落桿,每次只允許進(jìn)一輛車(chē),如果是手動(dòng)模式,可以由保安控制門(mén)閘打開(kāi),等10輛車(chē)都進(jìn)去之后,再由保安將門(mén)閘關(guān)閉。 總結(jié) 多線(xiàn)程技術(shù)雖然強(qiáng)大,但也伴隨著一定的復(fù)雜性和風(fēng)險(xiǎn)。理解其本質(zhì),并熟練掌握 .NET 框架提供的工具和最佳實(shí)踐,可以幫助大家更好地面對(duì)這些問(wèn)題,充分利用多核 CPU 的性能優(yōu)勢(shì)。隨著 .NET 框架的不斷演進(jìn),多線(xiàn)程編程變得越來(lái)越簡(jiǎn)單和安全,為程序開(kāi)發(fā)提供了堅(jiān)實(shí)的基礎(chǔ)。 該文章在 2025/6/13 10:22:06 編輯過(guò) |
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)... |