互斥体实际上没有被释放吗?

时间:2018-10-26 11:58:36

标签: c# asp.net-web-api2 mutex

我有一个Web api控制器,我想限制它一次只能运行一次。如果有新请求,我希望它被拒绝而不是排队。我已经使用Mutex实现了此行为,如以下代码所示:

public IHttpActionResult Get()
{
    string token = Utils.GetCurrentToken(RequestContext);
    //Some irrelevant code

    Task.Factory.StartNew(() =>
    {
        var mutexName = Utils.GetDBFromToken(token).ProjectID.ToString();

        var success = Mutex.TryOpenExisting(mutexName, out Mutex mutex);
        if (!success || mutex == null)
        {
            mutex = new Mutex(true, mutexName);
            Utils.Log(token, mutexName + " - Mutex created");
        }
        else
        {
            Utils.Log(token, mutexName + " - Mutex exists");
            return;
        }

        try
        {
            mutex.WaitOne();

            try
            {
                Utils.Log(token, mutexName + " - Job started");
                Thread.Sleep(10000);
                Utils.Log(token, mutexName + " - Job ended");
            }
            catch (Exception ex)
            {
                //Handle error
            }
        }
        finally
        {
            Utils.Log(token, mutexName + " - About to release mutex");
            if (mutex != null)
            {
                mutex.ReleaseMutex();
                mutex.Close();
                mutex.Dispose();
                Utils.Log(token, mutexName + " - Mutex released");
            }
        }
    });

    return Ok();
}

现在,如果我成功调用控制器3次,则会得到以下日志,这正是我期望的结果:

2018-10-26 11:45:11.650 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Mutex created
2018-10-26 11:45:11.870 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Mutex exists
2018-10-26 11:45:11.963 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Mutex exists
2018-10-26 11:45:12.323 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Job started
2018-10-26 11:45:22.633 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Job ended
2018-10-26 11:45:22.947 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - About to release mutex
2018-10-26 11:45:23.290 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Mutex released

但是,如果在释放并关闭后再次调用它,我会得到

2018-10-26 11:46:35.133 d6e4dd2e-16f1-43aa-b34b-226187dd9185 - Mutex exists

互斥量释放后TryOpenExisting不会失败吗?我在做错什么吗?

2 个答案:

答案 0 :(得分:2)

您应该考虑使用Monitor.TryEnter,而不是使用Mutex

它的功能类似于lock,但是如果已经获得了锁定,则会立即(根据需要)返回。

为此,您需要声明一个static锁定对象:

private static object lockObject;

或者,如果您需要多个锁(例如,每个数据库),则可以将这些锁存储在以下位置:

private static ConcurrentDictionary<string, object> lockObjects = new ConcurrentDictionary<string, object>();

使用GetOrAdd获取锁定对象。

此外,如果您使用的是Web Farm / Web Garden /负载均衡器,则此将不起作用(因为锁定将特定于进程)。如果这对您来说是个问题,我会考虑使用queue-每个Web服务器将条目添加到队列中,而单个队列使用方退出队列并删除请求。 < / p>

答案 1 :(得分:0)

您是否真的需要有关Mutex是否存在的逻辑?

为什么不总是使用var mutex = new Mutex(true, mutexName);?您无需检查它是否存在。而且Mutex.TryOpenExisting的检查也不是线程安全的。

编辑

还有一个问题,您在这里需要Mutex吗,LOCK是否足够?您是否打算在同一服务器上运行此WebAPI的多个实例?如果没有,那么一个锁应该足够了。

Mutex-跨流程工作

Lock-跨线程工作