【问题标题】:Cancelling task from taskschedule cancels all other tasks in it从 taskschedule 取消任务会取消其中的所有其他任务
【发布时间】: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 的单个实例,当我试图取消一个实例时,我会为所有任务提出取消请求。我说的对吗?

标签: task-parallel-library


【解决方案1】:

其实很简单:

您正在使用一个取消令牌作为字段。

 readonly CancellationTokenSource _cts = new CancellationTokenSource();

如果您只想取消一项任务,则需要为每个任务创建一个令牌,并且只取消传递给您要中止的任务的令牌。就这么简单:)

【讨论】:

    猜你喜欢
    • 2014-04-19
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多