线程 0 调用硬件异步 API, 拿到数据后, 从 devices 根据 id 取到 Device 实例, 更新硬件最新数据到这个实例上.
同时有多个监控线程每隔 100 毫秒读取一次所有设备状态, 并根据设备状态执行一次或多次耗时较长的异步操作, 并在异步操作执行完成后, 对硬件数据进行部分更新.
这个要怎么做才能确保线程安全?
// 设备集中存储处
ConcurrentDictionary[i] devices = new();
// 设备类
public class Device
{
public int Id { get; init; }
public bool Enable { get; set; }
public string Group { get; init; } = "";
public int[] Locations { get; init; } = Array.Empty[i]();
public int Margin { get; set; }
public int RsCount { get; init; }
public bool EnableSplit { get; init; }
public int DynamicMerge { get; set; }
public int Width { get; set; }
public int Length { get; set; }
public int LeftLength { get; set; }
public int LoadEdge { get; set; }
public int Dest { get; set; }
}
// 数据更新线程相关
public Thread0Executor()
{
public async Task Execute()
{
var data = await GetDataFromHardwareApi();
Update(data, devices);
}
}
// 数据监控处理线程相关
public MonitorThreadExecutor()
{
public async Task Execute()
{
Resolve(devices);
await Operate0();
DoSomething();
await Operate1();
DoSomething();
}
public async Task Operate0()
{
try
{
await CallApi();
Update(devices);
}
catch()
{
UpdateIfError(devices);
}
}
}
异步方法中根本没办法使用锁, 顶多用用信号量 Semaphore 来代替锁.
这里也不能对整个 Execute 方法用锁. 因为监控线程中的异步操作耗时是不一定的, 可能因为网络问题花个几分钟都有可能.
貌似也没法仅对非异步代码进行加锁, 因为同步异步代码是混杂在一块的, 没法单独对非异步代码进行加锁.
也考虑过弄个类似 ANDROID 里的 UI 线程和子线程的东西, 数据读取和更新都放在 UI 线程里, 异步操作放在子线程里. 但是搞了半天没搞出来.
最后的最后, 实在没办法了, 我在想要不把 Device 的所有属性都加一个 volatile 关键字. 我这里更新数据的时候基本不会看原来数据是多少, 不会出现count++这种情况, 貌似 volatile 是可行的. 但是实际这个 Device 有几十个属性, 并且有一两千个 Device, 如果每个属性都加一个 volatile 关键字, 那就是 2000*50=100 万个属性带 volatile 了. 这会不会极大地影响程序运行性能?