ASP.NET HostedService线程安全单例



在读/写单例中使用的List内部的项时,我需要关心线程安全吗
如果是,我需要锁定Foo.ValueFooManager.FooList的getter/setter吗?

我知道读取并向List添加项是不安全的,但我不确定这是否也适用于我的代码。

示例代码:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

public class Program
{
public static void Main()
{
var manager = new FooManager();
manager.FooList.Add(new Foo());
manager.FooList.Add(new Foo());
manager.FooList.Add(new Foo());

var updater = new FooUpdater(manager);
updater.UpdateAsync();
}
}
public class FooManager // Singleton
{
public List<Foo> FooList {get;set;}

public FooManager()
{
FooList = new List<Foo>();
}
}
public class Foo
{
public string Value {get; set;}
public async Task UpdateValue(string value)
{
await Task.Delay(10000);
Value = value;
}
}
public class FooUpdater // HostedService
{
private readonly FooManager _foomanager;
public FooUpdater(FooManager foomanager)
{
_foomanager = foomanager;
}
public async Task UpdateAsync()
{
while(true)
{
foreach(var foo in _foomanager.FooList)
{
await foo.UpdateValue("AAA");
}
}
}
}
public class FooController // Api Controller
{
private readonly FooManager _fooManager;
public FooController(FooManager foomanager)
{
_fooManager = foomanager;
}
// ...
// Read or write to foomanager.FooList items value
}

您的代码中存在2个潜在的线程安全问题

  1. 同时从多个线程写入/更新到List<T>

    解决方案:使用ConcurrentQueue<T>(请参阅下面的@TheodorZoulias评论(而不是List<T>,因为您不会通过索引访问项目,这非常适合。

  2. 有可能同时从HostedServiceFooController更新相同的foo对象(foo.UpdateValue(string)(。

    解决方案:您需要使foo类中的UpdateValue方法线程安全。很抱歉,我不能给你提供示例代码,因为你在帖子中没有提供实际的(比实际更简单的(代码。

如果是,我需要锁定Foo.Value或FooManager.FooList的getter/setter吗?

锁定FooManager.FooList的getter/setter没有任何用处。如果类型不是具有原子读/写的类型(例如double(,您应该锁定Foo.Value,更好地锁定所有类型,但我认为如果我们不锁定,值不会被破坏,所以我个人通常不会锁定,因为我不关心线程之间的值一致性。