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

实现思路

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

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

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

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

代码实现

cs 复制代码
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. 读取线程逻辑
cs 复制代码
while (!_stopRequested)
{
    if (_pauseRequest.IsSet)
    {
        _pausedConfirmed.Set();    // 确认已暂停
        _pauseRequest.Wait();      // 等待恢复信号
        _pausedConfirmed.Reset();  // 重置确认信号
    }
    // 执行读取操作...
}
  • 每次循环检查暂停请求。

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

3. 写入线程逻辑
cs 复制代码
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 安全终止线程。

相关推荐
昏睡红猹19 分钟前
C#脚本化(Roslyn):如何在运行时引入nuget包
c#
张人玉1 小时前
C# 常量与变量
java·算法·c#
m0_623955661 小时前
Oracle使用SQL一次性向表中插入多行数据
数据库·sql·oracle
就是有点傻2 小时前
在C#中,可以不实例化一个类而直接调用其静态字段
c#
软件黑马王子2 小时前
C#系统学习第八章——字符串
开发语言·学习·c#
阿蒙Amon2 小时前
C#读写文件:多种方式详解
开发语言·数据库·c#
东窗西篱梦2 小时前
Redis集群部署指南:高可用与分布式实践
数据库·redis·分布式
就是有点傻3 小时前
C#如何实现中英文快速切换
数据库·c#
1024小神3 小时前
hono框架绑定cloudflare的d1数据库操作步骤
数据库
KellenKellenHao5 小时前
MySQL数据库主从复制
数据库·mysql