方案核心思路
-
写入请求队列 :使用
ConcurrentQueue
接收来自任意线程的写入请求。 -
专用写入线程:由独立线程处理队列中的写入操作,确保顺序执行。
-
双信号机制 :通过
ManualResetEventSlim
控制读取线程的暂停与恢复。 -
线程安全确认:确保多个线程同时触发写入时,不会导致竞态条件。
完整代码实现
cs
using System;
using System.Collections.Concurrent;
using System.Threading;
public class CrossThreadReadWriteController
{
// 控制读取线程暂停和恢复的信号
private readonly ManualResetEventSlim _pauseRequest = new ManualResetEventSlim(false);
// 读取线程确认已暂停的信号
private readonly ManualResetEventSlim _pausedConfirmed = new ManualResetEventSlim(false);
// 写入请求队列(线程安全)
private readonly ConcurrentQueue<Action> _writeQueue = new ConcurrentQueue<Action>();
// 停止标志
private volatile bool _stopRequested = false;
// 写入专用线程
private Thread _writeThread;
public CrossThreadReadWriteController()
{
// 启动写入专用线程
_writeThread = new Thread(ProcessWriteQueue);
_writeThread.Start();
}
// 读取线程的循环任务
public void ReadLoop()
{
while (!_stopRequested)
{
// 检查是否需要暂停
if (_pauseRequest.IsSet)
{
// 确认已暂停,并等待恢复信号
_pausedConfirmed.Set();
_pauseRequest.Wait();
_pausedConfirmed.Reset();
}
// 模拟读取操作
Console.WriteLine($"[Read] {DateTime.Now:HH:mm:ss.fff} - Reading data...");
Thread.Sleep(1000); // 模拟耗时操作
}
Console.WriteLine("[Read] Thread stopped.");
}
// 处理写入队列的专用线程
private void ProcessWriteQueue()
{
while (!_stopRequested || !_writeQueue.IsEmpty)
{
if (_writeQueue.TryDequeue(out var writeAction))
{
// 触发暂停读取线程
RequestPause();
// 执行写入操作
writeAction.Invoke();
// 恢复读取线程
ResumeRead();
}
else
{
Thread.Sleep(50); // 队列为空时短暂休眠
}
}
Console.WriteLine("[Write] Thread stopped.");
}
// 跨线程提交写入请求
public void SubmitWriteCommand(Action writeAction)
{
_writeQueue.Enqueue(writeAction);
}
// 请求暂停读取线程(线程安全)
private void RequestPause()
{
_pauseRequest.Set();
_pausedConfirmed.Wait(); // 等待读取线程确认暂停
}
// 恢复读取线程(线程安全)
private void ResumeRead()
{
_pauseRequest.Reset();
}
// 停止所有线程
public void Stop()
{
_stopRequested = true;
_pauseRequest.Set(); // 确保读取线程退出等待
_writeThread.Join(); // 等待写入线程结束
}
}
// 使用示例
public class Program
{
public static void Main()
{
var controller = new CrossThreadReadWriteController();
// 启动读取线程
var readThread = new Thread(controller.ReadLoop);
readThread.Start();
// 模拟多个线程触发写入操作
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); // 模拟耗时操作
});
}).Start();
}
Thread.Sleep(5000); // 等待所有写入完成
controller.Stop();
readThread.Join();
Console.WriteLine("Main thread exited.");
}
}
关键改进解析
1. 跨线程写入请求的提交
通过 SubmitWriteCommand
方法,任何线程均可提交写入操作:
cs
public void SubmitWriteCommand(Action writeAction)
{
_writeQueue.Enqueue(writeAction); // 线程安全入队
}
2. 专用写入线程处理队列
写入操作由独立线程顺序处理,避免多线程并发写入冲突:
cs
private void ProcessWriteQueue()
{
while (!_stopRequested || !_writeQueue.IsEmpty)
{
if (_writeQueue.TryDequeue(out var writeAction))
{
RequestPause(); // 暂停读取线程
writeAction(); // 执行写入
ResumeRead(); // 恢复读取线程
}
}
}
3. 双重信号确保原子性
通过 RequestPause
和 ResumeRead
方法封装暂停与恢复逻辑:
cs
private void RequestPause()
{
_pauseRequest.Set(); // 发送暂停信号
_pausedConfirmed.Wait(); // 阻塞等待读取线程确认暂停
}
4. 线程安全停止机制
通过 _stopRequested
标志和队列检查确保安全退出:
cs
public void Stop()
{
_stopRequested = true;
_writeThread.Join(); // 等待写入线程处理完队列
}
运行效果
[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.
方案优势
特性 | 说明 |
---|---|
多线程安全 | 通过 ConcurrentQueue 和信号量,支持任意线程触发写入操作。 |
顺序执行 | 写入操作由专用线程顺序处理,避免并发冲突。 |
无锁读取 | 读取线程在非写入状态下完全无锁,最大化性能。 |
精准控制 | 通过双信号机制确保写入操作执行期间读取线程完全暂停。 |
适用场景
-
分布式任务调度:多个工作线程提交写入请求,由中心线程处理。
-
实时数据采集:采集线程持续读取数据,外部线程动态更新配置。
-
高并发服务:如网络服务器,处理来自不同客户端的并发更新操作。
注意事项
-
队列积压风险:若写入操作频率过高,需监控队列长度或添加背压机制。
-
异常处理:在写入操作中需捕获异常,避免导致写入线程崩溃。
-
性能调优 :可根据场景调整
Thread.Sleep
时间或使用无等待策略。