PureBasic

CreateSemaphore()

Синтаксис

Semaphore = CreateSemaphore([InitialCount])

Описание


Создаёт новый объект Семафор.

Семафор это объект синхронизации потоков, содержащий внутренний счётчик. Он имеет два вида операций: сигнал и ожидание. Операция ожидания уменьшает счётчик Семафора на единицу. Если счётчик был равен 0, операция ожидания заблокирует поток пока не придёт вызов сигнала. Операция сигнал увеличивает счётчик на единицу, освобождая заблокированный поток если такой есть. Семафор позволяет установить минимум и максимум для счётчика, например для того, чтобы очередь не опустела или не переполнилась.

В отличие от Мьютекса, объект Семафор не "принадлежит" конкретному потоку, что означает, что вызовы сигнал/ожидание не обязательно должны быть из одного и того же потока, как в случае функций LockMutex() и UnlockMutex(). Фактически, типичное использование объектов Семафоров: один поток делает вызовы функции SignalSemaphore(), а другой делает все вызовы функции WaitSemaphore(), реализуя шаблон производитель/потребитель.

Параметры

InitialCount (дополн.) Этот параметр должен быть положительным значением, он задаёт начальное значение счётчика Семафора. Если он не задан, начальное значение счётчика равно 0.

Возвращаемое значение

Возвращает идентификационный Номер Семафора, если он был успешно создан, в противном случае 0.

Пример

Этот пример показывает поток "производитель", заполняющий очередь элементами, и главный поток, читающий их. Семафор используется чтобы гарантировать, что очередь никогда не опустеет. Заметьте, того же можно добиться с помощью только Мьютекса и операций ожидания/опроса очереди вперемежку с вызовами функции Delay(), но команды Семафора реализуют более эффективное ожидание (возвращаясь сразу из вызова функции SignalSemaphore(), а не в следующий раз, когда цикл опроса проверит очередь).
Global Semaphore = CreateSemaphore()
Global Mutex     = CreateMutex()
Global NewList Queue()

Procedure Producer(Total)

  For i = 1 To Total
    Delay(Random(750) + 250)
    
    ; Работа с очередью всё же требует нормальной блокировки через Мьютекс для потокобезопасности
    LockMutex(Mutex)
      LastElement(Queue())
      AddElement(Queue())
      Queue() = i
    UnlockMutex(Mutex)    

    ; Сигнализируем, что в очереди новый элемент
    SignalSemaphore(Semaphore)
  Next i
    
EndProcedure

If CreateThread(@Producer(), 30)

  For i = 1 To 30  
    ; ожидаем наличия одного элемента
    WaitSemaphore(Semaphore)
    
    ; отображаем состояние очереди
    LockMutex(Mutex)
      Queue$ = "Queue:"
      ForEach Queue()
        Queue$ + " " + Str(Queue())
      Next Queue()
      Debug Queue$
    
      ; удаляем головной элемент из очереди
      FirstElement(Queue())
      DeleteElement(Queue())
    UnlockMutex(Mutex)
    
  Next i

EndIf

См. также

FreeSemaphore()

Поддерживаемые OS

Все

<- CreateMutex() - Оглавление Thread - CreateThread()->