ASP.NET метод блокировки потока - PullRequest
3 голосов
/ 30 марта 2010

Я разрабатываю веб-приложение для ASP.NET форм с использованием C #. У меня есть метод, который создает новый заказ для клиента. Похоже на это;

    private string CreateOrder(string userName) {
        // Fetch current order
        Order order = FetchOrder(userName);
        if (order.OrderId == 0) {
            // Has no order yet, create a new one
            order.OrderNumber = Utility.GenerateOrderNumber();
            order.Save();
        }
        return order;
    }

Проблема здесь в том, что один клиент в двух запросах (потоках) может вызвать двойной вызов этого метода, в то время как другой поток также находится внутри этого метода. Это может привести к созданию двух заказов.

Как правильно заблокировать этот метод, чтобы он мог выполняться только одним потоком за раз для каждого клиента?

Я пытался;

    Mutex mutex = null;
    private string CreateOrder(string userName) {
        if (mutex == null) {
            mutex = new Mutex(true, userName);
        }
        mutex.WaitOne();
        // Code from above
        mutex.ReleaseMutex();
        mutex = null;
        return order;
    }

Это работает, но в некоторых случаях зависает на WaitOne, и я не знаю почему. Есть ли ошибка, или я должен использовать другой метод для блокировки?

Спасибо

Ответы [ 6 ]

1 голос
/ 30 марта 2010

Pass false для initiallyOwned в mutex ctor. Если вы создаете мьютекс и изначально им владеете, вам нужно снова вызвать ReleaseMutex.

1 голос
/ 30 марта 2010

В своем коде вы лениво создаете мьютекс. Это приводит к условиям гонки.
Например. может случиться так, что мьютекс создается только частично, когда вы вызываете WaitOne () из другого потока.
Также может случиться, что вы создадите два экземпляра мьютекса.
и т.д ...

Вы можете избежать этого, создавая экземпляр с нетерпением - то есть, как в коде Майкла. (Обязательно инициализируйте его как не принадлежащее государству.)

Mutex - это примитив синхронизации на уровне ядра - он дороже, чем Monitor (это то, что lock использует.).

1 голос
/ 30 марта 2010

Вы должны всегда наконец попытаться при освобождении мьютекса. Также убедитесь, что ключ правильный (userName)

Mutex mutex = null;
private string CreateOrder(string userName) {
    mutex = mutex ?? new Mutex(true, userName);
    mutex.WaitOne();
    try{
    // Code from above
    }finally{
    mutex.ReleaseMutex();
    }
    mutex = null;
    return order;
}
0 голосов
/ 15 января 2013

Это проще сделать:

определить класс где-то так:

public class MyLocks {
    public static object OrderLock;
    static MyLocks() {
        OrderLock = new object();
    }
}

затем при использовании блокировки сделайте следующее:

lock(MyLocks.OrderLock) {
    // put your code here
}

Тогда это не очень сложно. Его легкий вес для определения блокировок для любых целей, поскольку они представляют собой очень крошечные объекты в памяти, которые живут в нескольких потоках.

0 голосов
/ 30 марта 2010

Я всегда избегал блокировок в веб-приложении - пусть веб-сервер обрабатывает потоки и вместо этого создает функцию обнаружения дубликатов.

Как вы думаете, что вы получите, заблокировав CreateOrder? Мне кажется, что вы можете избежать создания двух ордеров одновременно, но вы все равно будете в итоге создавать два ордера.

0 голосов
/ 30 марта 2010

Если я что-то упустил, вы не можете просто использовать обычную блокировку?

private object _locker = new object();

private string CreateOrder(string userName)
{
    lock(_locker)
    {
        // Fetch current order
        Order order = FetchOrder(userName);
        if (order.OrderId == 0)
        {
            // Has no order yet, create a new one
            order.OrderNumber = Utility.GenerateOrderNumber();
            order.Save();
        }
        return order;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...