Семафорная гонка? - PullRequest
       8

Семафорная гонка?

0 голосов
/ 21 апреля 2010

Я создал класс «Менеджер», который содержит ограниченный набор ресурсов. Ресурсы хранятся в «Диспетчере» как Очередь. Я инициализирую очередь и семафор одинакового размера, используя семафор для блокировки потока, если нет доступных ресурсов. У меня есть несколько потоков, вызывающих этот класс для запроса ресурса. Вот код псевдо:

public IResource RequestResource()
{
     IResource resource = null;
     _semaphore.WaitOne();

     lock (_syncLock)
     {
         resource = _resources.Dequeue();
     }
     return resource;
}
public void ReleaseResource(IResource resource)
{
    lock (_syncLock)
    {
        _resources.Enqueue(resource);
    }
    _semaphore.Release();
}

При запуске этого приложения оно некоторое время работает нормально. Затем, похоже, моя очередь выдает тот же объект. Кажется ли это возможным? Я тяну свои волосы сюда, и любая помощь будет принята с благодарностью. Не стесняйтесь спрашивать дополнительную информацию, если вам это нужно. Спасибо!

Ответы [ 2 ]

2 голосов
/ 21 апреля 2010

Семафор действительно случайный здесь; это просто ограничивает количество потребителей, которые могут приобретать ресурсы одновременно. Синхронизация на самом деле происходит из оператора lock (критический раздел).

Насколько я могу судить, этот код является поточно-ориентированным. Когда вы говорите, что «выдает один и тот же объект» - возможно, я неправильно понимаю вопрос, но должен выдавать тот же объект, потому что когда вызывающие вызывают метод Release, они возвращают тот же ресурс, который они получили изначально, поэтому один и тот же объект будет находиться в очереди в нескольких точках во время выполнения.

Если вы имеете в виду, что метод RequestResource возвращает ресурсы, которые уже были получены, но не освобождены, есть только три возможные причины, по которым я могу подумать:

  1. В очереди содержались повторяющиеся ресурсы с начала;

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

  3. Какой-то другой код обращается к очереди _resources без lock.

Мое подозрение будет №2, если это действительно то, что вы подразумеваете под дубликатами.

0 голосов
/ 21 апреля 2010

В дополнение к ответу Аарона:

Также вполне возможно, что два потока получат семафор, затем один войдет в критическую секцию в RequestResource(), а другой блок, после которого первый поток завершит всю свою работу и вернет объект в очередь с ReleaseResource() перед вторым потоком, просыпающимся и имеющим шанс удалить из очереди. Это создаст впечатление, что два потока получают один и тот же объект.

...