Мутекс на самом деле не выпускают? - PullRequest
0 голосов
/ 26 октября 2018

У меня есть контроллер веб-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

Но если я позвоню еще раз после вызова release и close, я просто получу

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

Не должно ли произойти сбой TryOpenExisting после освобождения мьютекса?Я что-то не так делаю?

Ответы [ 2 ]

0 голосов
/ 26 октября 2018

Вместо использования Mutex следует рассмотреть Monitor.TryEnter .

Он работает как lock, но сразу же возвращается (как вы хотите), если блокировка уже снята.

Для этого вам нужно объявить static объект блокировки:

private static object lockObject;

Или, если вам нужно несколько блокировок (например, для каждой базы данных), вы должны хранить эти блокировки в:

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

получение объекта блокировки с использованием GetOrAdd .

Кроме того, это не будет не работать, если вы также используете веб-ферму / веб-сад / балансировщик нагрузки (поскольку блокировка будет зависеть от конкретного процесса). Если это проблема для вас, я бы подумал об использовании queue - при этом каждый веб-сервер добавляет записи в очередь, а один потребитель очереди вытаскивает очередь и отменяет запросы.

0 голосов
/ 26 октября 2018

Вам действительно нужна логика вокруг того, существует ли Mutex или нет?

Почему бы не всегда использовать var mutex = new Mutex(true, mutexName);?Вы НЕ ДОЛЖНЫ проверять, существует ли он или нет.И эта проверка Mutex.TryOpenExisting также не является поточно-ориентированной.

РЕДАКТИРОВАТЬ

Еще один вопрос, нужен ли вам здесь Mutex, будет ли LOCK недостаточным?Планируете ли вы запускать несколько экземпляров этого WebAPI на одном сервере?Если нет, то блокировки должно быть достаточно.

Mutex - Работа в процессах

Lock - Работа в потоках

...