【发布时间】:2021-12-03 20:53:39
【问题描述】:
我想问一个我想到的问题。这个关于内存访问的问题,包含在 asp.net 核心中具有单例生命周期的对象。所以,假设这个结构中存在两个线程。其中之一是在 asp net 中使用的普通请求/响应线程。另一个线程在后台持续运行worker服务。
我的计划是创建任务队列。在队列中,我正在存储我不想在请求/响应线程中执行的任务。这个存储的函数在后台连续执行。
此代码分区包含到任务队列。所以这个类在后台工作服务和 asp.net 中的任何地方使用。
public class EventQueue : IEventQueue
{
public LinkedList<Task> Queue = new LinkedList<Task>();
public void AddEvent(Task task)
{
Queue.AddFirst(task);
}
public Task GetNextEvent()
{
var task = Queue.Last.Value;
Queue.RemoveLast();
return task;
}
}
此代码分区包含工作人员服务。它在队列任务中一一执行
public class QueueWorker : BackgroundService
{
private readonly IEventQueue _queue;
public QueueWorker(IEventQueue queue)
{
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var task = _queue.GetNextEvent();
if (task != null)
task.RunSynchronously();
}
}
}
此代码分区包含已注册的服务。
services.AddSingleton<IEventQueue,EventQueue>();
services.AddHostedService<QueueWorker>();
问题:
- 这种结构效果好吗?我认为,它不会很好地工作,因为有多个访问队列实例。或者更确切地说,工作服务总是在访问队列实例。因此将没有时间访问其他线程。那么这种做法对吗?
- 如果不使用单例生命周期并且 EventQueue 是静态的(至少 LinkedList 属性是静态的),情况会有所不同吗?
- 您对此结构有何改进建议?
【问题讨论】:
-
@quain 已经为您提供了解决方案,所以我只是在代码示例中指出了一些问题。
LinkedList不是线程安全的,这意味着如果多个线程进入它的成员(例如调用 Add/Remove 方法),它们可能会弄乱它的内部结构。这是主要问题。但是在您的GetNextEvent方法中使用了第二个模式:获取最后一个值并将其从列表中单独删除也不是线程安全的!第二个线程也可能在第一个线程删除它之前获得最后一个值! -
我明白了。我将使用线程安全对象(带锁机制)。根据下面的答案,我必须使用并发数据结构或 Task.Factory.StartNew()
标签: c# asp.net .net multithreading memory-management