| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- using System;
- using System.Threading;
- namespace IvfTl.Hardware.Impl
- {
- /// <summary>
- /// 按舱借用闸门实现。同一舱同一时刻只有一个使用者持有 lease。
- /// 优先级:前台(OperateDebug/AutoFocus) > 后台(ControlCapture)。
- /// · 前台申请借用时,先置暂停标志并触发 OnPauseCapture(采集线程每节拍据此让路);
- /// · 用 SemaphoreSlim(1) 保证舱级独占;后台采集 Acquire 用短超时,拿不到即返回 null 让调用方跳过本轮;
- /// · 归还(lease.Dispose) 时若已无前台占用则触发 OnResumeCapture。
- /// ⚠ 真机验证 V-012:借用→暂停→归还恢复时序(调试↔采集切换不占用/不死锁)。
- /// </summary>
- public sealed class HouseGateImpl : IHouseGate
- {
- private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
- private readonly object _stateLock = new object();
- private readonly Func<ISerialChannel> _serialFactory;
- private readonly Func<ICamera> _cameraFactory;
- private int _foregroundHolders = 0; // 当前前台借用计数(>0 时采集应暂停)
- public HouseGateImpl(int houseSn, Func<ISerialChannel> serialFactory, Func<ICamera> cameraFactory)
- {
- HouseSn = houseSn;
- _serialFactory = serialFactory;
- _cameraFactory = cameraFactory;
- }
- public int HouseSn { get; }
- public bool IsCapturePaused { get; private set; }
- public event Action OnPauseCapture;
- public event Action OnResumeCapture;
- public IHardwareLease Acquire(HardwareUser user, int timeoutMs = 30000)
- {
- bool foreground = user != HardwareUser.ControlCapture;
- // 前台借用:先标记暂停采集,让后台节拍尽快让路,再排队拿独占锁。
- if (foreground)
- {
- MarkPause();
- }
- bool got = _sem.Wait(timeoutMs);
- if (!got)
- {
- // 拿不到:前台撤销暂停标记(避免误挂起采集);后台直接返回 null 让调用方跳过本轮。
- if (foreground) MarkResume();
- return null;
- }
- return new HardwareLeaseImpl(this, user, _serialFactory(), _cameraFactory(), foreground);
- }
- public bool TryAcquire(HardwareUser user, out IHardwareLease lease)
- {
- bool foreground = user != HardwareUser.ControlCapture;
- if (foreground) MarkPause();
- if (!_sem.Wait(0))
- {
- if (foreground) MarkResume();
- lease = null;
- return false;
- }
- lease = new HardwareLeaseImpl(this, user, _serialFactory(), _cameraFactory(), foreground);
- return true;
- }
- public void PauseCapture() => MarkPause();
- public void ResumeCapture() => MarkResume();
- private void MarkPause()
- {
- bool fire = false;
- lock (_stateLock)
- {
- _foregroundHolders++;
- if (!IsCapturePaused)
- {
- IsCapturePaused = true;
- fire = true;
- }
- }
- if (fire) OnPauseCapture?.Invoke();
- }
- private void MarkResume()
- {
- bool fire = false;
- lock (_stateLock)
- {
- if (_foregroundHolders > 0) _foregroundHolders--;
- if (_foregroundHolders == 0 && IsCapturePaused)
- {
- IsCapturePaused = false;
- fire = true;
- }
- }
- if (fire) OnResumeCapture?.Invoke();
- }
- // 归还:释放独占锁;若是前台借用,撤销其暂停占用并按需恢复采集。
- internal void Release(bool wasForeground)
- {
- try { _sem.Release(); } catch { }
- if (wasForeground) MarkResume();
- }
- }
- /// <summary>借用凭证实现。Dispose 即归还闸门并(前台)触发 ResumeCapture。</summary>
- internal sealed class HardwareLeaseImpl : IHardwareLease
- {
- private readonly HouseGateImpl _gate;
- private readonly bool _foreground;
- private int _disposed = 0;
- public HardwareLeaseImpl(HouseGateImpl gate, HardwareUser owner, ISerialChannel serial, ICamera camera, bool foreground)
- {
- _gate = gate;
- _foreground = foreground;
- Owner = owner;
- Serial = serial;
- Camera = camera;
- }
- public HardwareUser Owner { get; }
- public ISerialChannel Serial { get; }
- public ICamera Camera { get; }
- public void Dispose()
- {
- // 幂等:多次 Dispose / using 异常路径只归还一次。
- if (Interlocked.Exchange(ref _disposed, 1) == 1) return;
- _gate.Release(_foreground);
- }
- }
- }
|