namespace MoShiro.Measurement; /// 一个运行中的积木:自己的取消令牌和后台任务。拨号方和监听方共用。 public sealed class RunningBlock : IDisposable { private readonly CancellationTokenSource _cts = new(); private RunningBlock(IBlock block, string signature) { Block = block; Signature = signature; Completion = Task.CompletedTask; } public IBlock Block { get; } /// 参数、端口或流编号变化时调和器据此重启积木。 public string Signature { get; } /// 积木自己结束(单向数据流的发送端)或失败()时完成;被 停止时正常完成。 public Task Completion { get; private set; } public static RunningBlock Start(IBlock block, string signature) { var running = new RunningBlock(block, signature); running.Completion = Task.Run(() => block.RunAsync(running._cts.Token), CancellationToken.None); return running; } /// 停止积木并等它退出(最多 5 秒)。 public async Task StopAsync() { await _cts.CancelAsync(); try { await Completion.WaitAsync(TimeSpan.FromSeconds(5)); } catch (Exception ex) when (ex is OperationCanceledException or TimeoutException or BlockFaultException) { // 没有及时退出或者已经失败:不再等 } Dispose(); } public void Dispose() => _cts.Dispose(); }