一个线程更新数据, 多个线程读数据, 这种怎么保证线程安全?

15次阅读

共计 1358 个字符,预计需要花费 4 分钟才能阅读完成。

.Net 相关
线程 0 调用硬件异步 API, 拿到数据后, 从 devices 根据 id 取到 Device 实例, 更新硬件最新数据到这个实例上.
同时有多个监控线程每隔 100 毫秒读取一次所有设备状态, 并根据设备状态执行一次或多次耗时较长的异步操作, 并在异步操作执行完成后, 对硬件数据进行部分更新.
这个要怎么做才能确保线程安全?

    // 设备集中存储处
    ConcurrentDictionary 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();
        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 了. 这会不会极大地影响程序运行性能?

正文完
 0