线程安全字典,具有项目使用计数和自动清理功能

问题描述 投票:0回答:1

如何实现线程安全的自动清理字典?

EventBusManager
必须为每个 roomId 提供一个
EventBus
实例。
EventBusManager
用法:

// When user connect to room
var eventBus = evtBusManager.GetIncrementUsage(roomId);

// When user disconnect
evtBusManager.DecrementUsage(roomId);

EventBusManager
实施:

public class EventBusManager {
    readonly Dictionary<string, BusUsage> buses = [];

    public EventBus GetIncrementUsage(string roomId) {
        lock (buses) {
            if (!buses.TryGetValue(roomId, out var busUsage)) {
                busUsage = new BusUsage(new EventBus());
                buses.Add(roomId, busUsage);
                return busUsage.Bus;
            }

            busUsage.UsageCount++;
            return busUsage.Bus;
        }
    }

    public void DecrementUsage(string roomId) {
        lock (buses) {
            if (!buses.TryGetValue(roomId, out var busUsage))
                return;

            busUsage.UsageCount--;

            if (busUsage.UsageCount == 0)
                buses.Remove(roomId);
        }
    }

    record BusUsage(EventBus Bus) {
        public int UsageCount = 1;
    };
}

实现线程安全吗?

c# .net multithreading dictionary concurrency
1个回答
0
投票

基本上,它看起来在功能上是线程安全的,但您的代码中存在一个策略错误。您不应使用字段

buses
作为锁定对象。惯用的技术是这样的:

请注意,字段

lockObject
应始终为
private

public class EventBusManager {       
    //...
    public EventBus GetIncrementUsage(string roomId) {
        lock (lockObject) {
            //...
            return busUsage.Bus;
        }
    }
    public void DecrementUsage(string roomId) {
        lock (lockObject) {
            //...
        }
    }
    object lockObject = new();
    // System.Threading.Lock lockObject = new(); // for .NET 9 and up
}

您可以在这里找到背后的一些理由。特别指出的一点是,锁对象应该是一个不用于任何其他目的的实例。

谢谢。
—SA

© www.soinside.com 2019 - 2024. All rights reserved.