ASP.NET HostedService 线程安全单例

ASP.NET HostedService thread safe singleton

当 read/writing 到单例中使用的 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. Writing/Updating 到 List<T> 同时来自多个线程。

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

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

    解决方案: 你需要使 foo class 中的 UpdateValue 方法是线程安全的。抱歉,我无法为您提供示例代码,因为您没有在 post.

    中提供实际的(比实际更简单的)代码

If so, do I need to lock the getter/setter of Foo.Value or FooManager.FooList?

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