【发布时间】:2015-10-08 21:28:07
【问题描述】:
首先,我对多线程特别是 tpl 真的很陌生,所以下面的代码可能很糟糕。真的很糟糕:)
所以,我有以下目标: 有任务队列,任务内联进行,任务“工作”的进度应该在进度条上。
我超负荷了TaskScheduler 班级:
public class MyTaskScheduler:TaskScheduler
{
[ThreadStatic]
private static bool _currentThreadIsProcessingItems;
private static Logger _logger;
private readonly TaskQueue _scheduledTasks;
private readonly int _maxDegreeOfParallelism;
private int _delegatesQueuedOrRunning = 0;
public MyTaskScheduler(int maxDegreeOfParallelism)
{
_logger = LogManager.GetLogger("log");
_maxDegreeOfParallelism = maxDegreeOfParallelism;
_scheduledTasks = new TaskQueue();
}
public override int MaximumConcurrencyLevel { get { return 1; } }
protected override IEnumerable<Task> GetScheduledTasks()
{
lock (_scheduledTasks)
{
return _scheduledTasks.ToList();
}
}
protected override void QueueTask(Task task)
{
lock (_scheduledTasks)
{
_scheduledTasks.Enqueue(task);
if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
{
++_delegatesQueuedOrRunning;
NotifyThreadPoolOfPendingWork();
}
}
_logger.Info("Task queued");
}
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
if (!_currentThreadIsProcessingItems) return false;
if (taskWasPreviouslyQueued)
if (TryDequeue(task))
return TryExecuteTask(task);
else
return false;
return TryExecuteTask(task);
}
private void NotifyThreadPoolOfPendingWork()
{
ThreadPool.UnsafeQueueUserWorkItem(_ =>
{
_currentThreadIsProcessingItems = true;
try
{
while (true)
{
Task item;
lock (_scheduledTasks)
{
if (_scheduledTasks.Count == 0)
{
--_delegatesQueuedOrRunning;
break;
}
item = _scheduledTasks.Dequeue();
}
_logger.Info("Execution of thread with id {0} started",item.Id);
TryExecuteTask(item);
_logger.Info("Execution of thread with id {0} ended", item.Id);
MessageBox.Show("ggg");
}
}
finally
{
_currentThreadIsProcessingItems = false;
}
}
, null);
}
}
还有我初始化队列的部分代码:
private readonly List<Task> _tasks = new List<Task>();
readonly CancellationTokenSource _cts = new CancellationTokenSource();
private MyTaskScheduler _scheduler;
readonly TaskFactory _factory;
private int _currentNumberOfThreads;
public Form1(bool isMainForm)
{
InitializeComponent();
_logger = LogManager.GetLogger("log");
_isMainForm = isMainForm;
_currentNumberOfThreads = 0;
_scheduler = new MyTaskScheduler(1);
_factory = new TaskFactory(_scheduler);
if (_isMainForm == false)
{
_currentNumberOfThreads++;
var t = _factory.StartNew(() => DoWork(_cts.Token), _cts.Token);
_tasks.Add(t);
}
在我尝试取消当前任务之前,它运行良好。
private void button2_Click(object sender, EventArgs e)
{
_logger.Info("Initialized cancelling of current thread");
_cts.Cancel();
_currentNumberOfThreads--;
}
这不仅取消了当前任务,还取消了队列中的所有任务,我可以从日志中看到:
01:56:18 Task queued
01:56:18 Execution of thread with id 1 started
01:56:18 Thread's DoWork() begun
01:56:19 Task queued
01:56:22 Task queued
01:56:30 Thread {0} DoWork() ended
01:56:30 Execution of thread with id 1 ended
01:56:31 Execution of thread with id 2 started
01:56:31 Thread's DoWork() begun
01:56:32 Task queued
01:56:32 Task queued
01:56:33 Task queued
01:56:34 Initialized cancelling of current thread
01:56:34 Execution of thread with id 2 ended
01:56:35 Execution of thread with id 3 started
01:56:35 Execution of thread with id 3 ended
01:56:36 Execution of thread with id 4 started
01:56:36 Execution of thread with id 4 ended
01:56:36 Execution of thread with id 5 started
01:56:36 Execution of thread with id 5 ended
01:56:37 Execution of thread with id 6 started
01:56:37 Execution of thread with id 6 ended
任务取消应该只取消当前任务,队列中的下一个任务应该开始并照常工作。
我真的很困惑,不知道我做错了什么。我有一个想法,CancellationTokenSource我曾经取消我的任务,是指整个时间表,而不是具体的任务,但我自己无法证明。因此,我们将不胜感激。
附:对不起我的英语不好。
【问题讨论】:
-
是的,似乎我正在为我的所有任务使用 CancellationToken 的单个实例,当我试图取消一个实例时,我会为所有任务提出取消请求。我说的对吗?