在static方法中正确锁定变量

时间:2018-06-13 08:33:13

标签: c# locking

我正在使用SignalR通知客户一些变化。 我的中心(但知道它是一个SignalR中心并不是根本)定义为

public class NotificationHub : Hub
{
    private static readonly IHubContext HubContext = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();

    private static readonly IDictionary<int, string> UserConnectionMapping = new Dictionary<int, string>();

    private static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    private const string UserId = "UserId";

    private readonly object userConnectionMappingLock = new object();



    public static void Static_UpdateStatus(int userId, string message)
    {
      lock(userConnectionMappingLock ) //This causes troubles
      {
         if (UserConnectionMapping.ContainsKey(userId))
        {
            var connectionId = UserConnectionMapping[userId];

            HubContext.Clients.Client(connectionId).updateNotifications(message);
        }
     }
 }
 public override Task OnConnected()
    {
        if (Context.QueryString[UserId] == null) return base.OnConnected();

        var userId = int.Parse(Context.QueryString[UserId]);
        Log.Debug($"User {userId} connected on SignalR with Connection Id {Context.ConnectionId}");

        lock (userConnectionMappingLock)
        {
            UserConnectionMapping[userId] = Context.ConnectionId;
        }

        return base.OnConnected();
    }

因为它是静态的方法(并且因为我需要从外部类访问所以不能这样),我是否应该声明锁定静态?考虑一下只有一个NotifyHub实例。感谢

1 个答案:

答案 0 :(得分:1)

你锁定的东西和被保护的东西应该具有相同的寿命和范围;目前UserConnectionMappingstatic,而userConnectionMappingLock是每个实例,这是灾难的处方。

坦率地说,static词典总是有点危险,但可以安全使用;选项:

  1. 使userConnectionMappingLock符合字典的范围 - 将static添加到userConnectionMappingLock(或从static删除UserConnectionMapping,请参阅3)
  2. 完全丢失userConnectionMappingLock (只是扔掉它),并在字典本身上lock UserConnectionMapping
  3. 使UserConnectionMapping 成为static - 因此每个中心实例都有一个字典(假设NotificationHub的生命周期适用于此)
  4. 使用ConcurrentDictrionary<int,string>
  5. 我可能会倾向于最后一个 - 你不太可能用它来射击你的脚。虽然我认为可以在1/2 / 4中使用3 以及中的任何一个。