使用异步方法

时间:2016-09-26 12:34:10

标签: c# .net asynchronous timer synchronization

我们的应用程序管理客户端订阅并将加载的项目保存在内存中。当最后一个客户端与项目断开连接时,在延迟之后,项目将被卸载。

卸载项目是一种异步方法,因为它涉及通过网络进行远程服务器通信。

如果另一个客户端在触发卸载计时器的同时订阅要卸载的项目,则会发生不好的事情。

如何同步?

不允许在UnloadProject块中调用等待的lock方法。它被认为是危险的,可能会失败,但实际上我根本不需要异步调用。如果我可以进行lock同步来序列化所有客户端订阅请求,我很乐意将异步方法称为同步并等待结果。并行执行可能很好,但它不适用于互斥的操作(如共享资源)。

我怀疑这个问题不仅限于我们这里的Timer,而是适用于异步方法需要围绕它们进行同步的任何情况。

这是代码,在我看到同步差距的位置有一个“TODO”注释:

public void ClientSubscribeProject(string projectUrlName)
{
    lock (clientSubscriptions)
    {
        // Initialise or increment counter
        if (!clientSubscriptions.ContainsKey(projectUrlName))
        {
            clientSubscriptions.Add(projectUrlName, 1);
        }
        else
        {
            clientSubscriptions[projectUrlName]++;
        }

        // Abort pending timer
        if (unloadTimers.ContainsKey(projectUrlName))
        {
            unloadTimers[projectUrlName].Change(Timeout.Infinite, Timeout.Infinite);
            unloadTimers[projectUrlName].Dispose();
            unloadTimers.Remove(projectUrlName);
        }
    }
}

public void ClientUnsubscribeProject(string projectUrlName)
{
    lock (clientSubscriptions)
    {
        // Decrement counter
        clientSubscriptions[projectUrlName]--;

        // Clear 0 counter and start timer
        if (clientSubscriptions[projectUrlName] == 0)
        {
            var timer = new Timer(
                async (state) =>
                {
                    lock (clientSubscriptions)
                    {
                        if (clientSubscriptions.ContainsKey(projectUrlName))
                            return;   // Another client has subscribed in this moment
                    }
                    // TODO: <-- Still a synchronisation gap!
                    await UnloadProject(projectUrlName);
                },
                null,
                300000,   // 5 minutes
                Timeout.Infinite);

            unloadTimers.Add(projectUrlName, timer);
            clientSubscriptions.Remove(projectUrlName);
        }
    }
}

0 个答案:

没有答案