Files
lserp_cs_6.0/插件库/Lskj.Util/TaskUtil.cs
T

131 lines
5.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Lskj.Util
{
public class TaskSchedulerUtil : TaskScheduler
{
/// <summary>
/// WinForms 会在后台线程第一次构造控件时自动安装
/// WindowsFormsSynchronizationContext。预加载任务只能执行数据准备,
/// 不应把线程池线程注册成 WinForms UI 线程;否则 DevExpress manager
/// 会绑定到已经没有消息循环的线程,导致模块打开/关闭后的残留和卡死。
/// 这里只在线程池任务执行期间使用一个非 WinForms 的同步上下文
/// 作为占位,不改变调度器的并发度,也不触碰真正的 UI 线程上下文。
/// 不能直接使用 SynchronizationContext 基类实例:WinForms 的
/// InstallIfNeeded 会把“基类实例”视为未安装状态并再次替换为
/// WindowsFormsSynchronizationContext;必须使用独立派生类型。
/// </summary>
private void ExecuteTaskWithoutWinFormsContext(Task task)
{
SynchronizationContext previousContext =
SynchronizationContext.Current;
bool replaceContext = previousContext == null ||
previousContext is WindowsFormsSynchronizationContext;
if (replaceContext)
{
SynchronizationContext.SetSynchronizationContext(
new BackgroundSynchronizationContext());
}
try
{
TryExecuteTask(task);
}
finally
{
if (replaceContext)
{
SynchronizationContext.SetSynchronizationContext(
previousContext);
}
}
}
/// <summary>
/// 标记后台线程已明确配置同步上下文,阻止 WinForms 按“空/基类上下文”
/// 自动安装 WindowsFormsSynchronizationContext。继承基类的默认 Post
/// 实现仍将延续任务投递到线程池,不改变普通后台任务语义。
/// </summary>
private sealed class BackgroundSynchronizationContext : SynchronizationContext
{
public override SynchronizationContext CreateCopy()
{
return new BackgroundSynchronizationContext();
}
}
private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); //任务队列
private readonly int _maxDegreeOfParallelism; //最大并发线程数
private int _runningTasks = 0; //当前正在运行的线程数
private readonly object _lock = new object(); //用于线程同步
public TaskSchedulerUtil(int maxDegreeOfParallelism)
{
if (maxDegreeOfParallelism < 1)
throw new ArgumentOutOfRangeException(nameof(maxDegreeOfParallelism));
_maxDegreeOfParallelism = maxDegreeOfParallelism;
}
// 将任务加入队列
protected override void QueueTask(Task task)
{
lock (_lock)
{
_tasks.AddLast(task); // 将任务加入队列
TryExecuteNextTask(); // 尝试执行下一任务
}
}
// 尝试执行下一个任务
private void TryExecuteNextTask()
{
lock (_lock)
{
// 如果当前运行的线程数小于最大并发数,且队列中还有任务
while (_runningTasks < _maxDegreeOfParallelism && _tasks.Count > 0)
{
var task = _tasks.First.Value;
_tasks.RemoveFirst(); // 取出一个任务
_runningTasks++; // 增加正在运行的任务计数
// 在线程池中运行任务
ThreadPool.QueueUserWorkItem(_ =>
{
try
{
ExecuteTaskWithoutWinFormsContext(task);
}
finally
{
lock (_lock)
{
_runningTasks--; // 减少正在运行的任务计数
TryExecuteNextTask(); // 尝试执行下一个任务
}
}
});
}
}
}
// 尝试在线程中直接运行任务(不支持)
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// 不允许直接在线程中运行任务(可以根据需求修改)
return false;
}
// 返回已计划的任务(用于调试)
protected override IEnumerable<Task> GetScheduledTasks()
{
lock (_lock)
{
return _tasks.ToList();
}
}
}
}