C#中實(shí)現(xiàn)跨線程寫入的示例代碼
方案核心思路
- 寫入請(qǐng)求隊(duì)列:使用
ConcurrentQueue接收來(lái)自任意線程的寫入請(qǐng)求。 - 專用寫入線程:由獨(dú)立線程處理隊(duì)列中的寫入操作,確保順序執(zhí)行。
- 雙信號(hào)機(jī)制:通過(guò)
ManualResetEventSlim控制讀取線程的暫停與恢復(fù)。 - 線程安全確認(rèn):確保多個(gè)線程同時(shí)觸發(fā)寫入時(shí),不會(huì)導(dǎo)致競(jìng)態(tài)條件。
完整代碼實(shí)現(xiàn)
using System;
using System.Collections.Concurrent;
using System.Threading;
public class CrossThreadReadWriteController
{
// 控制讀取線程暫停和恢復(fù)的信號(hào)
private readonly ManualResetEventSlim _pauseRequest = new ManualResetEventSlim(false);
// 讀取線程確認(rèn)已暫停的信號(hào)
private readonly ManualResetEventSlim _pausedConfirmed = new ManualResetEventSlim(false);
// 寫入請(qǐng)求隊(duì)列(線程安全)
private readonly ConcurrentQueue<Action> _writeQueue = new ConcurrentQueue<Action>();
// 停止標(biāo)志
private volatile bool _stopRequested = false;
// 寫入專用線程
private Thread _writeThread;
public CrossThreadReadWriteController()
{
// 啟動(dòng)寫入專用線程
_writeThread = new Thread(ProcessWriteQueue);
_writeThread.Start();
}
// 讀取線程的循環(huán)任務(wù)
public void ReadLoop()
{
while (!_stopRequested)
{
// 檢查是否需要暫停
if (_pauseRequest.IsSet)
{
// 確認(rèn)已暫停,并等待恢復(fù)信號(hào)
_pausedConfirmed.Set();
_pauseRequest.Wait();
_pausedConfirmed.Reset();
}
// 模擬讀取操作
Console.WriteLine($"[Read] {DateTime.Now:HH:mm:ss.fff} - Reading data...");
Thread.Sleep(1000); // 模擬耗時(shí)操作
}
Console.WriteLine("[Read] Thread stopped.");
}
// 處理寫入隊(duì)列的專用線程
private void ProcessWriteQueue()
{
while (!_stopRequested || !_writeQueue.IsEmpty)
{
if (_writeQueue.TryDequeue(out var writeAction))
{
// 觸發(fā)暫停讀取線程
RequestPause();
// 執(zhí)行寫入操作
writeAction.Invoke();
// 恢復(fù)讀取線程
ResumeRead();
}
else
{
Thread.Sleep(50); // 隊(duì)列為空時(shí)短暫休眠
}
}
Console.WriteLine("[Write] Thread stopped.");
}
// 跨線程提交寫入請(qǐng)求
public void SubmitWriteCommand(Action writeAction)
{
_writeQueue.Enqueue(writeAction);
}
// 請(qǐng)求暫停讀取線程(線程安全)
private void RequestPause()
{
_pauseRequest.Set();
_pausedConfirmed.Wait(); // 等待讀取線程確認(rèn)暫停
}
// 恢復(fù)讀取線程(線程安全)
private void ResumeRead()
{
_pauseRequest.Reset();
}
// 停止所有線程
public void Stop()
{
_stopRequested = true;
_pauseRequest.Set(); // 確保讀取線程退出等待
_writeThread.Join(); // 等待寫入線程結(jié)束
}
}
// 使用示例
public class Program
{
public static void Main()
{
var controller = new CrossThreadReadWriteController();
// 啟動(dòng)讀取線程
var readThread = new Thread(controller.ReadLoop);
readThread.Start();
// 模擬多個(gè)線程觸發(fā)寫入操作
for (int i = 0; i < 3; i++)
{
var threadId = i;
new Thread(() =>
{
controller.SubmitWriteCommand(() =>
{
Console.WriteLine($"[Write-{threadId}] {DateTime.Now:HH:mm:ss.fff} - Writing data...");
Thread.Sleep(500); // 模擬耗時(shí)操作
});
}).Start();
}
Thread.Sleep(5000); // 等待所有寫入完成
controller.Stop();
readThread.Join();
Console.WriteLine("Main thread exited.");
}
}關(guān)鍵改進(jìn)解析
1.跨線程寫入請(qǐng)求的提交
通過(guò) SubmitWriteCommand 方法,任何線程均可提交寫入操作:
public void SubmitWriteCommand(Action writeAction)
{
_writeQueue.Enqueue(writeAction); // 線程安全入隊(duì)
}2.專用寫入線程處理隊(duì)列
寫入操作由獨(dú)立線程順序處理,避免多線程并發(fā)寫入沖突:
private void ProcessWriteQueue()
{
while (!_stopRequested || !_writeQueue.IsEmpty)
{
if (_writeQueue.TryDequeue(out var writeAction))
{
RequestPause(); // 暫停讀取線程
writeAction(); // 執(zhí)行寫入
ResumeRead(); // 恢復(fù)讀取線程
}
}
}3.雙重信號(hào)確保原子性
通過(guò) RequestPause 和 ResumeRead 方法封裝暫停與恢復(fù)邏輯:
private void RequestPause()
{
_pauseRequest.Set(); // 發(fā)送暫停信號(hào)
_pausedConfirmed.Wait(); // 阻塞等待讀取線程確認(rèn)暫停
}4.線程安全停止機(jī)制
通過(guò) _stopRequested 標(biāo)志和隊(duì)列檢查確保安全退出:
public void Stop()
{
_stopRequested = true;
_writeThread.Join(); // 等待寫入線程處理完隊(duì)列
}運(yùn)行效果
[Read] 14:30:01.123 - Reading data...
[Read] 14:30:02.124 - Reading data...
[Write-0] 14:30:03.125 - Writing data...
[Read] 14:30:03.626 - Reading data...
[Write-1] 14:30:04.127 - Writing data...
[Read] 14:30:04.628 - Reading data...
[Write-2] 14:30:05.129 - Writing data...
Main thread exited.
方案優(yōu)勢(shì)
| 特性 | 說(shuō)明 |
|---|---|
| 多線程安全 | 通過(guò) ConcurrentQueue 和信號(hào)量,支持任意線程觸發(fā)寫入操作。 |
| 順序執(zhí)行 | 寫入操作由專用線程順序處理,避免并發(fā)沖突。 |
| 無(wú)鎖讀取 | 讀取線程在非寫入狀態(tài)下完全無(wú)鎖,最大化性能。 |
| 精準(zhǔn)控制 | 通過(guò)雙信號(hào)機(jī)制確保寫入操作執(zhí)行期間讀取線程完全暫停。 |
適用場(chǎng)景
- 分布式任務(wù)調(diào)度:多個(gè)工作線程提交寫入請(qǐng)求,由中心線程處理。
- 實(shí)時(shí)數(shù)據(jù)采集:采集線程持續(xù)讀取數(shù)據(jù),外部線程動(dòng)態(tài)更新配置。
- 高并發(fā)服務(wù):如網(wǎng)絡(luò)服務(wù)器,處理來(lái)自不同客戶端的并發(fā)更新操作。
注意事項(xiàng)
- 隊(duì)列積壓風(fēng)險(xiǎn):若寫入操作頻率過(guò)高,需監(jiān)控隊(duì)列長(zhǎng)度或添加背壓機(jī)制。
- 異常處理:在寫入操作中需捕獲異常,避免導(dǎo)致寫入線程崩潰。
- 性能調(diào)優(yōu):可根據(jù)場(chǎng)景調(diào)整
Thread.Sleep時(shí)間或使用無(wú)等待策略。
到此這篇關(guān)于C#中實(shí)現(xiàn)跨線程寫入的示例代碼的文章就介紹到這了,更多相關(guān)C# 跨線程寫入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C#中跨線程訪問(wèn)控件的實(shí)現(xiàn)方法
- C#?winform?窗體控件跨線程訪問(wèn)的實(shí)現(xiàn)
- C#?winform跨線程操作控件的實(shí)現(xiàn)
- C#多線程異步執(zhí)行和跨線程訪問(wèn)控件Helper
- C#-WinForm跨線程修改UI界面的示例
- 淺談C#跨線程調(diào)用窗體控件(比如TextBox)引發(fā)的線程安全問(wèn)題
- C#多線程與跨線程訪問(wèn)界面控件的方法
- C#實(shí)現(xiàn)跨線程操作控件方法
- C#之WinForm跨線程訪問(wèn)控件實(shí)例
- C#中跨線程訪問(wèn)控件問(wèn)題解決方案分享
相關(guān)文章
C#連接到sql server2008數(shù)據(jù)庫(kù)的實(shí)例代碼
這篇文章主要介紹了C#連接到sql server2008數(shù)據(jù)庫(kù)的實(shí)例代碼,需要的朋友可以參考下2017-09-09
C#實(shí)現(xiàn)讀取被進(jìn)程占用的文件實(shí)現(xiàn)方法
這篇文章主要介紹了C#實(shí)現(xiàn)讀取被進(jìn)程占用的文件實(shí)現(xiàn)方法,涉及C#進(jìn)程操作及文件讀取的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08
C#通過(guò)HttpWebRequest發(fā)送帶有JSON Body的POST請(qǐng)求實(shí)現(xiàn)
本文主要介紹了C#通過(guò)HttpWebRequest發(fā)送帶有JSON Body的POST請(qǐng)求實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
Silverlight文件上傳下載實(shí)現(xiàn)方法(下載保存)
這篇文章主要介紹了Silverlight文件上傳下載實(shí)現(xiàn)方法(下載保存) ,需要的朋友可以參考下2015-11-11
P/Invoke之C#調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL示例詳解
這篇文章主要為大家介紹了P/Invoke之C#調(diào)用動(dòng)態(tài)鏈接庫(kù)DLL示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
C#實(shí)現(xiàn)簡(jiǎn)單超市收銀系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)單超市收銀系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02

