请求取消时在同一线程内执行代码的实现方案
解决方案
核心思路是确保线程在取消触发或任务结束时,能在自身线程上下文内执行电源状态重置逻辑,避免while轮询。以下是两种可靠实现方式:
方式一:利用Rx的Finally操作符(适配你的Observable场景)
Rx的Finally操作符会在序列完成、报错或被取消时自动执行收尾逻辑,且能保证在调度器绑定的线程上运行(即你的目标线程):
private static void RunJob() { _tokenSource.Token.ThrowIfCancellationRequested(); bool success = false; try { success = SetUpThreadState(); if (success) { Observable.Timer(expireAt, Scheduler.CurrentThread) // 不管Timer触发还是被取消,都会执行重置 .Finally(() => ResetThreadState()) .Subscribe( t => CancelExistingThread(), _tokenSource.Token); } } catch (OperationCanceledException ex) { Log($"Background thread termination. Message: {ex.Message}"); // 处理订阅前就触发取消的场景 if (success) ResetThreadState(); } finally { // 处理方法正常退出的场景 if (success) ResetThreadState(); } } private static void ResetThreadState() { // 重置线程电源状态到默认 SetThreadExecutionState(ES_CONTINUOUS); }
方式二:用等待句柄阻塞线程,取消时唤醒执行重置
如果需要更直接控制线程生命周期,可借助ManualResetEvent让线程等待取消信号,触发后在自身上下文执行重置:
private static void RunJob() { _tokenSource.Token.ThrowIfCancellationRequested(); bool success = false; using var cancellationEvent = new ManualResetEvent(false); try { // 注册取消回调,触发时唤醒线程 using var _ = _tokenSource.Token.Register(() => cancellationEvent.Set()); success = SetUpThreadState(); if (success) { var subscription = Observable.Timer(expireAt, Scheduler.CurrentThread) .Subscribe( t => { CancelExistingThread(); cancellationEvent.Set(); // Timer触发后唤醒线程 }, _tokenSource.Token); // 等待取消或Timer触发,线程在此阻塞 WaitHandle.WaitAny(new[] { cancellationEvent, _tokenSource.Token.WaitHandle }); subscription.Dispose(); // 清理Rx订阅 } } catch (OperationCanceledException ex) { Log($"Background thread termination. Message: {ex.Message}"); } finally { // 最终在目标线程执行状态重置 if (success) ResetThreadState(); } } private static void ResetThreadState() { SetThreadExecutionState(ES_CONTINUOUS); }
关键注意事项
SetThreadExecutionState必须在目标线程调用,上述两种方式均保证重置逻辑在RunJob所在线程执行;- 确保
SetUpThreadState中使用正确的参数(如ES_CONTINUOUS | ES_SYSTEM_REQUIRED),重置时仅传递ES_CONTINUOUS即可恢复默认电源管理; - 若使用Rx方案,需确认
Scheduler.CurrentThread确实绑定到目标线程,避免跨线程执行重置逻辑。
内容的提问来源于stack exchange,提问作者Den
相关产品推荐
相关产品推荐

