gpt4 book ai didi

c# - 取消长时间运行的任务后如何正确清理

转载 作者:太空狗 更新时间:2023-10-29 21:59:26 30 4
gpt4 key购买 nike

我创建了一个类,其目的是抽象出对队列并发访问的控制。

该类旨在在单个线程上实例化,由多个线程写入,然后从后续的单个线程读取。

我在类中生成了一个长时间运行的任务,它将执行一个阻塞循环并在项目成功出列时触发一个事件。

我的问题是:我执行取消长时间运行的任务以及随后清理/重置 CancellationTokenSource 对象的正确用法吗?

理想情况下,我希望事件对象能够停止和重新启动,同时保持可用性以添加到队列中。

我以 Peter Bromberg 的文章为基础:Producer/Consumer Queue and BlockingCollection in C# 4.0

代码如下:

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace Test
{
public delegate void DeliverNextQueuedItemHandler<T>(T item);

public sealed class SOQueueManagerT<T>
{

ConcurrentQueue<T> _multiQueue;
BlockingCollection<T> _queue;
CancellationTokenSource _canceller;
Task _listener = null;

public event DeliverNextQueuedItemHandler<T> OnNextItem;

public bool IsRunning { get; private set; }
public int QueueSize
{
get
{
if (_queue != null)
return _queue.Count;
return -1;
}
}

public CancellationTokenSource CancellationTokenSource
{
get
{
if (_canceller == null)
_canceller = new CancellationTokenSource();

return _canceller;
}
}

public SOQueueManagerT()
{
_multiQueue = new ConcurrentQueue<T>();
_queue = new BlockingCollection<T>(_multiQueue);

IsRunning = false;
}

public void Start()
{
if (_listener == null)
{


IsRunning = true;

_listener = Task.Factory.StartNew(() =>
{

while (!CancellationTokenSource.Token.IsCancellationRequested)
{
T item;
if (_queue.TryTake(out item, 100))
{
if (OnNextItem != null)
{

OnNextItem(item);
}
}

}
},
CancellationTokenSource.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
}

public void Stop()
{
if (_listener != null)
{
CancellationTokenSource.Cancel();
CleanUp();
}
}

public void Add(T item)
{
_queue.Add(item);
}

private void CleanUp()
{
_listener.Wait(2000);
if (_listener.IsCompleted)
{
IsRunning = false;
_listener = null;
_canceller = null;
}
}


}
}

更新这就是我最后所做的。它并不完美,但到目前为止正在完成这项工作。

public sealed class TaskQueueManager<T> 
{
ConcurrentQueue<T> _multiQueue;
BlockingCollection<T> _queue;
CancellationTokenSource _canceller;
Task _listener = null;

public event DeliverNextQueuedItemHandler<T> OnNextItem;

public bool IsRunning
{
get
{
if (_listener == null)
return false;
else if (_listener.Status == TaskStatus.Running ||
_listener.Status == TaskStatus.Created ||
_listener.Status == TaskStatus.WaitingForActivation ||
_listener.Status == TaskStatus.WaitingToRun ||
_listener.IsCanceled)
return true;
else
return false;
}
}
public int QueueSize
{
get
{
if (_queue != null)
return _queue.Count;
return -1;
}
}

public TaskQueueManager()
{
_multiQueue = new ConcurrentQueue<T>();
_queue = new BlockingCollection<T>(_multiQueue);
}

public void Start()
{
if (_listener == null)
{
_canceller = new CancellationTokenSource();

_listener = Task.Factory.StartNew(() =>
{
while (!_canceller.Token.IsCancellationRequested)
{
T item;
if (_queue.TryTake(out item, 100))
{
if (OnNextItem != null)
{
try
{
OnNextItem(item);
}
catch (Exception e)
{
//log or call an event
}
}
}
}
},
_canceller.Token,
TaskCreationOptions.LongRunning,
TaskScheduler.Default);
}
}

public void Stop()
{
if (_listener != null)
{
_canceller.Cancel();

if (_listener.IsCanceled && !_listener.IsCompleted)
_listener.Wait();

_listener = null;
_canceller = null;
}
}

public void Add(T item)
{
if (item != null)
{
_queue.Add(item);
}
else
{
throw new ArgumentNullException("TaskQueueManager<" + typeof(T).Name + ">.Add item is null");
}
}
}

最佳答案

仔细的编程是唯一能解决问题的方法。即使您取消操作,您也可能有一个未在时尚时间内完成的挂起操作。它很可能是一个陷入僵局的阻塞操作。在这种情况下,您的程序实际上不会终止。

例如,如果我多次调用您的 CleanUp 方法,或者没有先调用 Start,我感觉它会崩溃。

清理期间的 2 秒超时,感觉比计划的更随意,实际上我会尽可能确保事情正常关闭或崩溃/挂起(你永远不想让并发的东西处于未知状态)。

此外,IsRunning 是显式设置的,不是从对象的状态推断出来的。

为了获得灵感,我希望您看看我最近写的一个类似的类,它是一种在后台线程中工作的生产者/消费者模式。您可以在 CodePlex 上找到该源代码.不过,这是为了解决一个非常具体的问题而设计的。

在这里,取消是通过查询只有工作线程识别的特定类型来解决的,因此开始关闭。这也确保我永远不会取消待处理的工作,只会考虑整个工作单元。

要稍微改善这种情况,您可以为当前工作设置一个单独的计时器,并在取消时中止或回滚未完成的工作。现在,实现类似事务的行为需要反复试验,因为您需要查看每个可能的极端情况并问问自己,如果程序在这里崩溃会怎样?理想情况下,所有这些代码路径都会导致可恢复或已知状态,您可以从中恢复工作。但正如我认为您已经猜到的那样,这需要仔细的编程和大量的测试。

关于c# - 取消长时间运行的任务后如何正确清理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5243872/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com