C# 中实现一个线程持续读取,另一个线程负责写入,且写入时读取线程暂停

发布于:2025-03-25 ⋅ 阅读:(34) ⋅ 点赞:(0)

实现思路

  1. 暂停信号通过 ManualResetEventSlim 通知读取线程暂停

  2. 暂停确认:读取线程收到暂停信号后,发送确认信号。

  3. 原子性控制:确保写入操作执行期间,读取线程处于完全暂停状态。

  4. 恢复机制写入完成后恢复读取线程。

代码实现

using System;
using System.Threading;

public class ReadWriteController
{
    // 控制读取线程暂停和恢复的信号
    private readonly ManualResetEventSlim _pauseRequest = new ManualResetEventSlim(false);
    // 读取线程确认已暂停的信号
    private readonly ManualResetEventSlim _pausedConfirmed = new ManualResetEventSlim(false);
    // 停止读取线程的标志
    private volatile bool _stopRequested = false;

    // 读取线程的循环任务
    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.");
    }

    // 写入操作的外部触发方法
    public void WriteCommand()
    {
        // 发送暂停请求
        _pauseRequest.Set();
        Console.WriteLine("[Write] Pause request sent.");

        // 等待读取线程确认暂停
        _pausedConfirmed.Wait();
        Console.WriteLine("[Write] Read thread paused. Starting write operation...");

        // 模拟写入操作(此处可替换为实际业务逻辑)
        Thread.Sleep(500); // 模拟耗时操作
        Console.WriteLine($"[Write] {DateTime.Now:HH:mm:ss.fff} - Write completed.");

        // 恢复读取线程
        _pauseRequest.Reset();
        Console.WriteLine("[Write] Read thread resumed.");
    }

    // 停止所有线程
    public void Stop()
    {
        _stopRequested = true;
        _pauseRequest.Set(); // 确保读取线程退出等待
    }
}

// 使用示例
public class Program
{
    public static void Main()
    {
        var controller = new ReadWriteController();

        // 启动读取线程
        var readThread = new Thread(controller.ReadLoop);
        readThread.Start();

        // 模拟写入操作(每隔3秒触发一次)
        for (int i = 0; i < 3; i++)
        {
            Thread.Sleep(3000);
            controller.WriteCommand();
        }

        // 停止所有线程
        controller.Stop();
        readThread.Join();
        Console.WriteLine("Main thread exited.");
    }
}

代码解析

1. 控制信号定义
  • _pauseRequest:写入线程通过 Set() 发送暂停请求,读取线程通过 Wait() 阻塞自身。

  • _pausedConfirmed:读取线程暂停后通过 Set() 通知写入线程,确保写入操作安全执行。

2. 读取线程逻辑
while (!_stopRequested)
{
    if (_pauseRequest.IsSet)
    {
        _pausedConfirmed.Set();    // 确认已暂停
        _pauseRequest.Wait();      // 等待恢复信号
        _pausedConfirmed.Reset();  // 重置确认信号
    }
    // 执行读取操作...
}
  • 每次循环检查暂停请求。

  • 若收到暂停信号,立即确认并阻塞自身,直到写入完成。

3. 写入线程逻辑
public void WriteCommand()
{
    _pauseRequest.Set();          // 发送暂停请求
    _pausedConfirmed.Wait();      // 等待读取线程确认暂停
    // 执行写入操作...
    _pauseRequest.Reset();        // 恢复读取线程
}
  • 写入前确保读取线程已完全暂停。

  • 写入完成后恢复读取线程。

运行效果

[Read] 14:25:03.456 - Reading data...
[Read] 14:25:04.457 - Reading data...
[Write] Pause request sent.
[Write] Read thread paused. Starting write operation...
[Write] 14:25:05.457 - Write completed.
[Write] Read thread resumed.
[Read] 14:25:05.958 - Reading data...
[Read] 14:25:06.959 - Reading data...
...
Main thread exited.

方案特点

  1. 严格同步通过双重信号机制确保写入操作插入的安全性

  2. 无竞态条件:使用 ManualResetEventSlim 避免多线程竞争。

  3. 可控停止:通过 _stopRequested 安全终止线程。