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 安全终止线程。

相关推荐
一氧化二氢.h1 分钟前
MySQL root用户连接错误解决方法
android·数据库·mysql
q***239215 分钟前
数据库操作与数据管理——Rust 与 SQLite 的集成
数据库·rust·sqlite
q***333719 分钟前
给SQL server数据库表字段添加注释SQL,附修改、删除注释SQL及演示
数据库·sql·oracle
百***221230 分钟前
mysql 迁移达梦数据库出现的 sql 语法问题 以及迁移方案
数据库·sql·mysql
_Jimmy_32 分钟前
ShardingSphere-JDBC 实现两个mysql数据库的不同表的关联查询
数据库·mysql
weixin_307779131 小时前
基于AWS的应用程序可靠性提升架构优化方案——RDS多可用区与EC2弹性架构实践
数据库·数据仓库·架构·云计算·aws
Chan161 小时前
【 Java八股文面试 | Redis篇 缓存问题、持久化、分布式锁 】
java·数据库·redis·后端·spring·缓存·面试
G***T6911 小时前
PostgreSQL全文搜索教程,中文分词配置
数据库·postgresql·中文分词
必胜刻2 小时前
MySQL复盘总结
数据库·mysql·oracle
百***79462 小时前
MySQL数据库(SQL分类)
数据库·sql·mysql