2010-12-15 3 views
2

Я использую простое блокирование в C# с помощью инструкции lock. Есть ли способ определить, сколько других потоков ожидает, чтобы получить блокировку объекта? Я в основном хочу ограничить количество потоков, ожидающих блокировки до 5. Мой код будет генерировать исключение, если шестой поток должен получить блокировку.Есть ли способ определить количество потоков, ожидающих блокировки на C#?

+6

Это звучит как вторая половина громоздкого решения. Какова проблема, которую вы пытаетесь решить? – 2010-12-15 21:25:49

+0

Болезненно объяснить, но у меня есть объект, который является оберткой стороннего веб-сервиса. Хитрость заключается в том, что вызовы сторонней службы должны быть синхронизированы, следовательно, блокировка объекта-обертки. Я использую объект-оболочку в среде веб-сайта, поэтому несколько потоков могут попытаться использовать его одновременно. Причина, по которой я хочу ограничить очередь ожидающих потоков до 5, заключается в том, что я немного обеспокоен тем, насколько легко было бы создать DoS-приложение. Сторонний веб-сервис работает очень медленно, поэтому кто-то может легко отправлять запросы, и у меня будет 100% заблокированных потоков. – 2010-12-15 21:34:57

+1

@Ben: Похоже, ресурс, который вам нужно ограничить, - это количество потоков в системе *, а не * сколько можно ждать при блокировке *. Никогда не делайте нить за запрос; сделать один поток на один процессор, и если у вас закончились процессоры, попросите клиента подождать, пока поток освободится. – 2010-12-15 21:43:20

ответ

3

Это можно легко выполнить с помощью класса Semaphore. Он будет делать подсчет для вас. Обратите внимание, что в приведенном ниже коде я использую семафор, чтобы выполнить неблокирующую проверку количества потоков, ожидающих ресурса, а затем я использую простой старый lock для фактического сериализации доступа к этому ресурсу. Исключение выдается, если на ресурс присутствует более 5 потоков.

public class YourResourceExecutor 
{ 
    private Semaphore m_Semaphore = new Semaphore(5, 5); 

    public void Execute() 
    { 
    bool acquired = false; 
    try 
    { 
     acquired = m_Semaphore.WaitOne(0); 
     if (!acquired) 
     { 
     throw new InvalidOperationException(); 
     } 
     lock (m_Semaphore) 
     { 
     // Use the resource here. 
     } 
    } 
    finally 
    { 
     if (acquired) m_Semaphore.Release(); 
    } 
    } 
} 

Существует один заметный вариант этого рисунка. Вы можете изменить имя метода на TryExecute и вернуть его bool вместо того, чтобы выбрасывать исключение. Это полностью зависит от вас.

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

1

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

1

Нет, lock() использует Monitor class и не имеет учетной записи, чтобы узнать о nr в очереди.

Вы можете указать тайм-аут.

И, откровенно говоря, бросать исключение, когда очередь заполняется, звучит как плохая идея.

2

Заявление о блокировке является ярлыком для Monitor.Enter и Monitor.Exit. Я не думаю, что у вас есть шанс получить количество ожидающих объектов.

Смежные вопросы