优化之前的代码,将 GlobalCache.TestPowerReadStatus 和 GlobalCache.TestPowerSetStatus 合并为一个公共状态(例如 GlobalCache.CanExecutePSRead),以简化状态管理,并满足以下要求:

  1. 统一状态控制:

    • 使用一个公共状态变量(CanExecutePSRead)来控制 PSRead 的执行。

    • 该状态基于硬件读取状态(AUXRealTimeState1.TestPowerStatus)和设置状态(AUXInsMap["TestPowerSet"])的组合逻辑:

      • 只有当硬件读取状态为 true 且设置状态不为 false 时,CanExecutePSRead = true,允许 PSRead。

      • 一旦设置状态为 false,CanExecutePSRead 立即变为 false,禁止 PSRead。

  2. 循环等待:

    • 在设置电压的地方(或其他需要等待的地方),可以通过循环等待 CanExecutePSRead = true 来决定是否跳出等待并执行后续操作(如设置电压)。

  3. 优化目标:

    • 简化状态管理,减少多个状态变量的维护成本。

    • 确保线程安全,防止多线程环境下状态冲突。

    • 支持循环等待机制,便于其他模块(如电压设置)使用。

    • 保持日志记录,便于调试。

问题:

  • 当前代码使用两个状态变量(TestPowerReadStatus 和 TestPowerSetStatus),管理复杂且容易出错。

  • PSRead 的调用条件需要明确检查两个状态,逻辑分散。

  • 没有提供循环等待 CanExecutePSRead = true 的机制,用于其他操作(如设置电压)。


优化方案

  1. 引入公共状态变量:

    • 使用 GlobalCache.CanExecutePSRead 作为统一的状态变量,替代 TestPowerReadStatus 和 TestPowerSetStatus。

    • CanExecutePSRead 的值由 UpdatePowerStatus 方法根据 AUXRealTimeState1.TestPowerStatus 和 AUXInsMap["TestPowerSet"] 计算:

      • CanExecutePSRead = AUXRealTimeState1.TestPowerStatus && Convert.ToBoolean(AUXInsMap["TestPowerSet"])

  2. 统一状态更新:

    • 在 AUXSET 和 Read 方法中调用公共的 UpdatePowerStatus 方法,更新 CanExecutePSRead。

    • 确保 AUXSET 设置 false 时,CanExecutePSRead 立即变为 false。

  3. 循环等待机制:

    • 提供一个方法(例如 WaitForPowerStatus),让其他模块(如电压设置)可以通过循环等待 CanExecutePSRead = true 来决定是否继续。

  4. 线程安全:

    • 使用 lock 保护 GlobalCache.CanExecutePSRead 的读写操作。

    • 确保等待机制在多线程环境下安全。

  5. 日志记录:

    • 记录状态变化和等待情况,便于调试。


优化后的代码

以下是优化后的完整代码,包含统一的公共状态管理和循环等待机制:

csharp

private readonly object _lock = new object(); // 用于线程安全

// 更新公共状态
private void UpdatePowerStatus()
{
    lock (_lock)
    {
        var readStatus = AUXRealTimeState1.TestPowerStatus; // 硬件读取状态
        var setStatus = Convert.ToBoolean(AUXInsMap["TestPowerSet"]); // 设置状态
        GlobalCache.CanExecutePSRead = readStatus && setStatus; // 只有两者都为 true 时才允许 PSRead
        Console.WriteLine($"UpdatePowerStatus: ReadStatus={readStatus}, SetStatus={setStatus}, CanExecutePSRead={GlobalCache.CanExecutePSRead}");
    }
}

// AUXSET 方法:响应设置状态变化
public void AUXSET()
{
    lock (_lock)
    {
        UpdatePowerStatus();
    }
}

// Read 方法:持续监控硬件状态
public void Read()
{
    while (!m_Dis)
    {
        lock (_lock)
        {
            UpdatePowerStatus();
        }
        Thread.Sleep(100); // 保留 100ms 轮询
    }
}

// PSRead 调用逻辑
public void ExecutePSRead()
{
    lock (_lock)
    {
        if (GlobalCache.CanExecutePSRead)
        {
            MingShengInterop.LabVIEWExports.PSRead(HWSelect,
                                                   out pSRealV,
                                                   out pSRealI,
                                                   out PSStatus,
                                                   out Error,
                                                   out dutRealV);
            Console.WriteLine("PSRead executed");
        }
        else
        {
            Console.WriteLine($"PSRead skipped: CanExecutePSRead={GlobalCache.CanExecutePSRead}");
        }
    }
}

// 循环等待 CanExecutePSRead 为 true(例如用于设置电压)
public bool WaitForPowerStatus(int timeoutMs = 5000, int pollIntervalMs = 100)
{
    var startTime = DateTime.Now;
    while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs)
    {
        lock (_lock)
        {
            if (GlobalCache.CanExecutePSRead)
            {
                Console.WriteLine("WaitForPowerStatus: CanExecutePSRead is true, exiting wait");
                return true;
            }
        }
        Console.WriteLine("WaitForPowerStatus: Waiting...");
        Thread.Sleep(pollIntervalMs); // 每 100ms 检查一次
    }
    Console.WriteLine($"WaitForPowerStatus: Timeout after {timeoutMs}ms");
    return false; // 超时未达到 true
}

// 示例:设置电压时等待 CanExecutePSRead 为 true
public void SetVoltage()
{
    if (WaitForPowerStatus(timeoutMs: 5000)) // 等待最多 5 秒
    {
        // 执行电压设置逻辑
        Console.WriteLine("SetVoltage: Power status is ready, setting voltage...");
        // 例如:CallVoltageSetFunction();
    }
    else
    {
        Console.WriteLine("SetVoltage: Failed to set voltage due to timeout or invalid power status");
    }
}

优化点说明

  1. 统一状态管理:

    • 引入 GlobalCache.CanExecutePSRead 作为公共状态变量,基于 AUXRealTimeState1.TestPowerStatus 和 AUXInsMap["TestPowerSet"] 的逻辑与(&&)计算。

    • UpdatePowerStatus 方法统一更新状态,确保:

      • 当硬件读取状态为 true 且设置状态为 true 时,CanExecutePSRead = true。

      • 当设置状态为 false 或硬件读取状态为 false 时,CanExecutePSRead = false。

    • 这满足“读取为真才可以 PSRead,一设置为 false 就停止”的需求。

  2. 循环等待机制:

    • 新增 WaitForPowerStatus 方法,允许其他模块(如电压设置)等待 CanExecutePSRead = true。

    • 参数:

      • timeoutMs:最大等待时间(默认 5000ms,即 5 秒)。

      • pollIntervalMs:轮询间隔(默认 100ms,与 Read 方法一致)。

    • 返回 true 表示状态变为 true,返回 false 表示超时。

    • 示例中,SetVoltage 方法调用 WaitForPowerStatus 等待状态就绪后再设置电压。

  3. 线程安全:

    • 所有状态访问(CanExecutePSRead)和更新(UpdatePowerStatus)都使用 lock (_lock),确保多线程安全。

    • WaitForPowerStatus 和 ExecutePSRead 也加锁,避免状态冲突。

  4. 日志记录:

    • 记录 UpdatePowerStatus 的输入(ReadStatus 和 SetStatus)和输出(CanExecutePSRead)。

    • 记录 PSRead 的执行情况和 WaitForPowerStatus 的等待过程,便于调试。

  5. 代码简洁性:

    • 合并状态管理到 UpdatePowerStatus,减少重复逻辑。

    • 将 PSRead 封装为单独方法 ExecutePSRead,提高代码复用性。

    • WaitForPowerStatus 提供通用等待机制,适用于其他需要等待状态的场景。


使用示例

假设你有一个设置电压的场景,需要等待电源状态就绪:

csharp

// 主程序
public void Main()
{
    // 启动 Read 线程(假设在后台运行)
    Task.Run(() => Read());

    // 设置电压
    SetVoltage();

    // 模拟设置状态变化
    AUXInsMap["TestPowerSet"] = false; // 设置为 false
    AUXSET(); // 更新状态
    ExecutePSRead(); // 不会执行,因为 CanExecutePSRead = false

    // 恢复设置状态
    AUXInsMap["TestPowerSet"] = true;
    AUXSET();
    SetVoltage(); // 再次等待状态
}

日志输出示例:

Read: ReadStatus=true, SetStatus=true, CanExecutePSRead=true
ExecutePSRead: PSRead executed
AUXSET: ReadStatus=true, SetStatus=false, CanExecutePSRead=false
ExecutePSRead: PSRead skipped: CanExecutePSRead=false
AUXSET: ReadStatus=true, SetStatus=true, CanExecutePSRead=true
WaitForPowerStatus: CanExecutePSRead is true, exiting wait
SetVoltage: Power status is ready, setting voltage...

进一步优化建议

  1. 异步等待机制:

    • 如果阻塞式等待(Thread.Sleep)影响性能,可将 WaitForPowerStatus 改为异步:

      csharp

      public async Task<bool> WaitForPowerStatusAsync(int timeoutMs = 5000, int pollIntervalMs = 100)
      {
          var startTime = DateTime.Now;
          while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs)
          {
              lock (_lock)
              {
                  if (GlobalCache.CanExecutePSRead)
                  {
                      Console.WriteLine("WaitForPowerStatusAsync: CanExecutePSRead is true, exiting wait");
                      return true;
                  }
              }
              Console.WriteLine("WaitForPowerStatusAsync: Waiting...");
              await Task.Delay(pollIntervalMs);
          }
          Console.WriteLine($"WaitForPowerStatusAsync: Timeout after {timeoutMs}ms");
          return false;
      }
      
      public async Task SetVoltageAsync()
      {
          if (await WaitForPowerStatusAsync(timeoutMs: 5000))
          {
              Console.WriteLine("SetVoltageAsync: Power status is ready, setting voltage...");
              // 例如:await CallVoltageSetFunctionAsync();
          }
          else
          {
              Console.WriteLine("SetVoltageAsync: Failed to set voltage due to timeout or invalid power status");
          }
      }
  2. 事件驱动替代轮询:

    • 如果硬件支持状态变更通知,可用事件替换 Read 的轮询:

      csharp

      public void Initialize()
      {
          AUXRealTimeState1.TestPowerStatusChanged += (sender, newStatus) =>
          {
              lock (_lock)
              {
                  UpdatePowerStatus();
              }
          };
      }
  3. 超时和错误处理:

    • 在 WaitForPowerStatus 中添加错误处理,例如记录硬件状态异常:

      csharp

      public bool WaitForPowerStatus(int timeoutMs = 5000, int pollIntervalMs = 100)
      {
          var startTime = DateTime.Now;
          while ((DateTime.Now - startTime).TotalMilliseconds < timeoutMs)
          {
              lock (_lock)
              {
                  if (GlobalCache.CanExecutePSRead)
                  {
                      Console.WriteLine("WaitForPowerStatus: CanExecutePSRead is true, exiting wait");
                      return true;
                  }
                  if (!Convert.ToBoolean(AUXInsMap["TestPowerSet"]))
                  {
                      Console.WriteLine("WaitForPowerStatus: SetStatus is false, aborting wait");
                      return false; // 设置为 false 直接退出
                  }
              }
              Console.WriteLine("WaitForPowerStatus: Waiting...");
              Thread.Sleep(pollIntervalMs);
          }
          Console.WriteLine($"WaitForPowerStatus: Timeout after {timeoutMs}ms");
          return false;
      }
  4. 状态变化通知:

    • 如果其他模块需要实时响应 CanExecutePSRead 变化,可使用事件或委托:

      csharp

      public delegate void PowerStatusChangedHandler(bool canExecute);
      public static event PowerStatusChangedHandler PowerStatusChanged;
      
      private void UpdatePowerStatus()
      {
          lock (_lock)
          {
              var readStatus = AUXRealTimeState1.TestPowerStatus;
              var setStatus = Convert.ToBoolean(AUXInsMap["TestPowerSet"]);
              var newStatus = readStatus && setStatus;
              if (newStatus != GlobalCache.CanExecutePSRead)
              {
                  GlobalCache.CanExecutePSRead = newStatus;
                  PowerStatusChanged?.Invoke(newStatus);
              }
              Console.WriteLine($"UpdatePowerStatus: ReadStatus={readStatus}, SetStatus={setStatus}, CanExecutePSRead={GlobalCache.CanExecutePSRead}");
          }
      }

总结

优化后的代码通过引入 GlobalCache.CanExecutePSRead 统一管理状态,基于 AUXRealTimeState1.TestPowerStatus 和 AUXInsMap["TestPowerSet"] 的逻辑与,确保:

  • 硬件读取状态为 true 且设置状态为 true 时,允许 PSRead。

  • 设置状态为 false 时,立即禁止 PSRead。

  • 提供 WaitForPowerStatus 方法,支持其他模块(如电压设置)等待状态就绪。

  • 线程安全和日志记录确保可靠性和可调试性。

如果有具体场景(如电压设置的具体逻辑、硬件响应时间或多线程细节),请提供更多信息,我可以进一步定制优化方案!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐