跳到主要内容

主动异步隔离 (Async Isolation)

本页是"主动异步隔离层"的参考。 它把 Build / SetState / SDO 读写 / 静态扫描这些会阻塞总线/邮箱的同步操作,包装成"入队即返回、后台串行执行、可取消、带进度"的异步版本,避免在 GUI / Service 线程上卡死,并保证同一主站任意时刻只有一个操作打总线

与语法糖页的区别 —— C# 语法糖 里的 SetStateAsync / CloseAsync 只是把单个同步调用推到线程池的"便捷写法";本页的隔离层多了每主站串行闸 (一次只放行一个操作)关闭守门 (防资源已释放后继续访问)取消时干净中断并自动恢复可用状态独立静态扫描闸四项工业级保证。两边并存,旧同步 API 全部保留。

六语言一致

C / C++ / Java / Python / Rust / C# 六语言 SDK 都提供同一套异步隔离能力,语义对齐本页 C# 参考,命名各随语言惯例(C# Async 后缀 + Task;Java CompletableFuture;Python async def + await;Rust async fn + .await;C/C++ 后台 worker + 完成回调)。

一、设计要点

要点实现
串行 (Serial)每主站一把串行闸(一次只放行一个操作)。同一主站的 Build / SetState / SDO 严格 FIFO 串行,绝不并发打总线/邮箱。SDO 经父主站同一把闸排队。
后台隔离 (Isolation)*Async 入队即返回,阻塞调用在线程池后台执行,不堵调用线程 / async runtime。
守门 (Shutdown Guard)Dispose / Close 先置关闭标志,释放底层资源。入队前 + 执行前各查一次,关闭中绝不再发起底层调用,防资源已释放后继续访问。
取消 (Cancel)取消令牌触发后中断正在执行的阻塞调用,并自动恢复到可用状态(无需应用层手动复位)。扫描走独立的取消通道,与主站操作互不干扰。
进度 (Progress)逐阶段上报进度回调。回调在后台线程触发,调用方需自己 marshal 回 UI。
进度回调在后台线程 — 必须自己 marshal

所有进度回调与完成回调都在后台工作线程触发,不是 UI 线程。WinForms 用 Control.BeginInvoke、WPF / Avalonia / MAUI 用 Dispatcher.InvokeAsync,否则跨线程访问 UI 控件会抛异常。

await master.BuildAsync(progress: msg =>
{
// ❌ 直接改 UI 会跨线程抛异常
// ✅ 必须 marshal 回 UI 线程
this.BeginInvoke(() => statusLabel.Text = msg);
});

二、API 总览

类别属性类型访问说明
主站一条龙BuildAsyncTask<bool>异步异步执行 连接→扫描→配置→进 OP 一条龙,带进度与取消
SetStateAsyncTask<bool>异步异步状态切换,经串行闸排队,带取消令牌
SetNetworkAsyncTask<int>异步异步设置主/冗余网卡(链式串行用)
从站 SDOSDOReadAsyncTask<byte[]>异步异步读 SDO,转调父主站同一把闸,失败返回 null
SDOWriteAsyncTask<bool>异步异步写 SDO,转调父主站同一把闸
静态扫描ScanAsyncTask<List<ScannedSlaveInfo>>异步异步静态扫描,走独立扫描闸 + 独立取消通道
生命周期CloseAsyncTask异步异步软停车 + 释放,先置关闭标志再释放底层资源
DisposeAsyncTask异步异步释放(CloseAsync 别名语义)
状态查询IsAsyncOperationInProgressbool只读当前是否有异步隔离操作在串行闸中执行
InitProgressevent Action<string>订阅初始化进度多播事件(后台线程触发)

三、方法详解

BuildAsync(Action<string> progress, CancellationToken ct)

public Task<bool> BuildAsync(Action<string> progress = null, CancellationToken ct = default)

异步执行"连接 → 扫描 → 配置 → 进 OP"一条龙构建。入队即返回 Task,构建在后台线程串行执行。

参数:

  • progress (Action<string>) — 进度回调,在后台线程触发,调用方自行 marshal 回 UI(可选)
  • ct (CancellationToken) — 取消令牌;取消时干净中断当前构建并自动恢复到可用状态(可选)

返回值:

  • Task<bool>true 构建成功并进入 OP,false 失败

示例:

var cts = new CancellationTokenSource();
bool ok = await master.BuildAsync(
progress: msg => this.BeginInvoke(() => statusLabel.Text = msg),
ct: cts.Token);
if (!ok) Console.WriteLine("构建失败");

SetStateAsync(EcState state, CancellationToken ct)

public Task<bool> SetStateAsync(EcState state, CancellationToken ct = default)

异步状态切换,经主站串行闸排队,与同主站的 Build / SDO 互斥串行。重试与 SafeOp 自动 SDO 行为同 同步 SetState

参数:

  • state (EcState) — 目标状态
  • ct (CancellationToken) — 取消令牌(可选)

返回值:

  • Task<bool>true 切换成功,false 失败

示例:

bool ok = await master.SetStateAsync(EcState.OP, ct);

SDOReadAsync / SDOWriteAsync (Slave)

public Task<byte[]> SDOReadAsync(ushort index, byte subIndex, bool completeAccess = false, CancellationToken ct = default)
public Task<bool> SDOWriteAsync(ushort index, byte subIndex, byte[] data, bool completeAccess = false, CancellationToken ct = default)

异步 SDO 读写。转调父主站的同一把串行闸,绝不与同主站的 PDO / 状态切换并发打邮箱。

参数:

  • index (ushort) — 对象字典索引
  • subIndex (byte) — 子索引
  • data (byte[]) — 写入数据(仅 write)
  • completeAccess (bool) — 完整访问(可选)
  • ct (CancellationToken) — 取消令牌(可选)

返回值:

  • SDOReadAsyncTask<byte[]>,失败返回 null
  • SDOWriteAsyncTask<bool>

示例:

byte[] data = await master.Slaves[0].SDOReadAsync(0x6041, 0x00, ct: ct);
bool wrote = await master.Slaves[0].SDOWriteAsync(0x6040, 0x00, new byte[]{0x06,0x00}, ct: ct);

ScanAsync(string adapter, string secondaryAdapter, CancellationToken ct)

public static Task<List<ScannedSlaveInfo>> ScanAsync(string adapter, string secondaryAdapter = null, CancellationToken ct = default)

异步静态扫描(不构建主站)。走进程级独立扫描闸,取消时走独立的扫描取消通道(与主站操作的取消严格区分,互不干扰)。

返回值:

  • Task<List<ScannedSlaveInfo>> — 扫描到的从站列表

示例:

var slaves = await DarraEtherCAT.ScanAsync("以太网", ct: ct);
foreach (var s in slaves) Console.WriteLine(s.Name);

CloseAsync / DisposeAsync(CancellationToken ct)

public Task CloseAsync(CancellationToken ct = default)
public Task DisposeAsync(CancellationToken ct = default)

异步软停车 + 释放。先置关闭守门标志,再释放底层资源 —— 此后入队的异步操作会被守门拒绝并以"已取消"完成,不再发起底层调用。

示例:

await master.CloseAsync(ct);

四、取消语义

取消令牌触发后,隔离层会中断正在执行的阻塞调用,并在中断完成后自动把内部状态恢复到可用:

操作类型取消行为
主站 Build / SetState / SDO中断当前主站操作,完成后自动恢复,下一个操作可正常入队
静态扫描 ScanAsync独立的扫描取消通道,与主站操作的取消互不影响
取消后自动恢复

中断后隔离层会自动把内部状态复位,确保后续的 Build / SetState 不会被上一次的取消影响。这一切由隔离层内置处理,应用层无需任何手动操作。

var cts = new CancellationTokenSource();
var task = master.BuildAsync(ct: cts.Token);

// 用户点取消按钮
cancelButton.Click += (_, _) => cts.Cancel();

try { await task; }
catch (OperationCanceledException) { Console.WriteLine("已取消"); }

五、串行性保证示意

master (单主站) ── 串行闸 (一次只放行一个) ──┐
├─► [后台 worker 串行]
BuildAsync ───┐ │ Build
SetStateAsync ├─► 入队 (FIFO) ───────────┤ SetState
SDOReadAsync ─┘ (同一把闸) │ SDO ...
│ 任意时刻只有 1 个打总线
ScanAsync (静态) ── 独立扫描闸 (独立取消通道) ─┘

兼容性

异步隔离层作为独立扩展提供,不修改任何已有同步 SDK 代码。原同步 Build / SetState / ScanSlaves / SDORead / SDOWrite 全部保留,向后兼容。