using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Sim.Host;
///
/// 教材项目 5 用到的旧版线程 API:Thread.Suspend / Resume / Abort 在新版 .NET 上会抛出 PlatformNotSupportedException。
/// 编译时把学生代码里对它们(以及 new Thread、Thread.Sleep、ThreadState)的调用改写成这里的方法(见 Sim.Runner/LegacyThreadRewriter.cs)。
///
/// 新版 .NET 不能从外部强行停住或中止一个线程,所以这里是"协作式"的:被挂起或中止的线程在下一个检查点停下或结束。
/// 检查点是 Thread.Sleep、从后台线程修改控件属性、调用设备类库、弹出提示框,
/// 教材里的线程方法每次循环都会经过它们,看到的效果和 .NET Framework 一致。
///
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static class LegacyThreads
{
private sealed class State
{
public volatile bool Suspended;
public volatile bool AbortRequested;
}
// 线程少、操作不频繁,用一把锁保护所有线程的状态;挂起和休眠都在这把锁上等待
private static readonly object Gate = new();
private static readonly ConditionalWeakTable States = new();
/// 当前线程是学生用 new Thread 创建的线程时,指向它的状态
[ThreadStatic] private static State? _current;
private static State StateOf(Thread thread) => States.GetValue(thread, static _ => new State());
// ---------- 改写后的调用 ----------
/// new Thread(GetData) → new Thread(Wrap(new ThreadStart(GetData))):线程被中止时安静地结束
public static ThreadStart Wrap(ThreadStart start) => () => RunThread(() => start());
public static ParameterizedThreadStart Wrap(ParameterizedThreadStart start) => obj => RunThread(() => start(obj));
private static void RunThread(Action body)
{
var state = StateOf(Thread.CurrentThread);
_current = state;
try
{
// 启动前就被 Abort 的线程(.NET Framework 里启动后立即结束)
CheckPoint(state);
body();
}
catch (ThreadAbortedException)
{
// 和 .NET Framework 一样,被中止的线程结束时不算未处理的异常
}
}
public static void Suspend(Thread thread)
{
lock (Gate)
{
if ((thread.ThreadState & (ThreadState.Unstarted | ThreadState.Stopped)) != 0)
throw new ThreadStateException("线程没有在运行,无法挂起。");
StateOf(thread).Suspended = true;
}
// 线程挂起自己:立即停下,直到别的线程调用 Resume
if (thread == Thread.CurrentThread) CheckPoint(StateOf(thread));
}
public static void Resume(Thread thread)
{
lock (Gate)
{
var state = StateOf(thread);
if (!state.Suspended) throw new ThreadStateException("线程没有被挂起,无法继续(Resume 只能用在调用过 Suspend 的线程上)。");
state.Suspended = false;
Monitor.PulseAll(Gate);
}
}
public static void Abort(Thread thread) => Abort(thread, null);
public static void Abort(Thread thread, object? stateInfo)
{
lock (Gate)
{
if ((thread.ThreadState & ThreadState.Stopped) != 0) return;
var state = StateOf(thread);
state.AbortRequested = true;
// 正在 Thread.Sleep 的线程立即醒来结束
Monitor.PulseAll(Gate);
// .NET Framework 不能直接中止挂起的线程:抛出异常,等它被 Resume 后才结束
if (state.Suspended) throw new ThreadStateException("线程已挂起,不能直接终止。先调用 Resume() 让线程继续,再调用 Abort()。");
}
if (thread == Thread.CurrentThread) throw new ThreadAbortedException();
}
/// thd.ThreadState:在真实状态上加上挂起、请求中止
public static ThreadState GetThreadState(Thread thread)
{
var actual = thread.ThreadState;
if (!States.TryGetValue(thread, out var state) || (actual & ThreadState.Stopped) != 0) return actual;
var result = actual & (ThreadState.Background | ThreadState.Unstarted);
if (state.Suspended) result |= ThreadState.Suspended;
else if ((actual & ThreadState.Unstarted) == 0) result |= actual & ThreadState.WaitSleepJoin;
if (state.AbortRequested) result |= ThreadState.AbortRequested;
return result;
}
public static void Sleep(int millisecondsTimeout)
{
var state = _current;
if (state == null)
{
Thread.Sleep(millisecondsTimeout);
return;
}
if (millisecondsTimeout < Timeout.Infinite) throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), "休眠时间不能是负数(-1 表示一直休眠)。");
CheckPoint(state);
var deadline = Environment.TickCount64 + millisecondsTimeout;
lock (Gate)
{
// 休眠中被 Abort 时提前醒来;被 Suspend 的线程睡完后在检查点停下
while (!state.AbortRequested)
{
if (millisecondsTimeout == Timeout.Infinite)
{
Monitor.Wait(Gate);
continue;
}
var remaining = deadline - Environment.TickCount64;
if (remaining <= 0) break;
Monitor.Wait(Gate, (int)remaining);
}
}
CheckPoint(state);
}
public static void Sleep(TimeSpan timeout) => Sleep((int)timeout.TotalMilliseconds);
// ---------- 检查点 ----------
/// 平台内部使用:学生创建的线程在这里响应 Suspend 和 Abort(其他线程直接返回)
public static void CheckPoint()
{
var state = _current;
if (state != null) CheckPoint(state);
}
private static void CheckPoint(State state)
{
if (!state.Suspended && !state.AbortRequested) return;
lock (Gate)
{
while (state.Suspended) Monitor.Wait(Gate);
if (state.AbortRequested) throw new ThreadAbortedException();
}
}
}
/// 线程被 Abort 时在线程里抛出(对应 .NET Framework 的 ThreadAbortException)
public sealed class ThreadAbortedException : Exception
{
public ThreadAbortedException() : base("正在中止线程。") { }
}