Подсчет семафоров может использоваться для защиты ресурсов, но обычно они используются для разных ресурсов по-разному, чем семафор мьютекса.
Типичным примером может быть очередь.Для динамически изменяемой очереди у вас есть подсчитанный семафор, чтобы отслеживать, сколько элементов в данный момент находится в очереди.Потребители ждут этого семафора, чтобы сообщить им, когда они могут прочитать элемент из очереди.
Для очереди фиксированного размера вы добавляете второй подсчитанный семафор, отслеживающий количество пустого пространства в очереди.Авторы ждут, чтобы определить, когда им разрешено помещать элемент в очередь.
Вы часто используете семафор мьютекса в сочетании с тем, чтобы убедиться, что только один поток изменяет саму очередь в любой данный моментвремя.
Например, вот код для очереди фиксированного размера, использующей семафоры с подсчетом Win32 (и мьютекс):
#ifndef QUEUE_H_INCLUDED
#define QUEUE_H_INCLUDED
#include <windows.h>
template<class T, unsigned max = 256>
class queue {
HANDLE space_avail; // at least one slot empty
HANDLE data_avail; // at least one slot full
CRITICAL_SECTION mutex; // protect buffer, in_pos, out_pos
T buffer[max];
long in_pos, out_pos;
public:
queue() : in_pos(0), out_pos(0) {
space_avail = CreateSemaphore(NULL, max, max, NULL);
data_avail = CreateSemaphore(NULL, 0, max, NULL);
InitializeCriticalSection(&mutex);
}
void push(T data) {
WaitForSingleObject(space_avail, INFINITE);
EnterCriticalSection(&mutex);
buffer[in_pos] = data;
in_pos = (in_pos + 1) % max;
LeaveCriticalSection(&mutex);
ReleaseSemaphore(data_avail, 1, NULL);
}
T pop() {
WaitForSingleObject(data_avail,INFINITE);
EnterCriticalSection(&mutex);
T retval = buffer[out_pos];
out_pos = (out_pos + 1) % max;
LeaveCriticalSection(&mutex);
ReleaseSemaphore(space_avail, 1, NULL);
return retval;
}
~queue() {
DeleteCriticalSection(&mutex);
CloseHandle(data_avail);
CloseHandle(space_avail);
}
};
#endif