Какое отношение имеет критический раздел к подсчету семафоров? - PullRequest
1 голос
/ 24 апреля 2019

Некоторые люди говорят, что вы должны использовать мьютексы для защиты общих ресурсов (то есть критических секций), в то время как семафоры должны использоваться для сигнализации, а не наоборот. Итак, насколько я понимаю, семафоры не имеют ничего общего с критическими разделами.

Однако во многих других статьях, включая Википедию , говорится, что семафоры используются для решения проблем критических секций. Действительно ли правильнее сказать, что двоичные семафоры решают проблемы критических секций, поскольку они в основном действуют как мьютексы, в то время как подсчет семафоров - это совсем другое и не относится к "защитникам ресурсов" "категория?

1 Ответ

1 голос
/ 25 апреля 2019

Подсчет семафоров может использоваться для защиты ресурсов, но обычно они используются для разных ресурсов по-разному, чем семафор мьютекса.

Типичным примером может быть очередь.Для динамически изменяемой очереди у вас есть подсчитанный семафор, чтобы отслеживать, сколько элементов в данный момент находится в очереди.Потребители ждут этого семафора, чтобы сообщить им, когда они могут прочитать элемент из очереди.

Для очереди фиксированного размера вы добавляете второй подсчитанный семафор, отслеживающий количество пустого пространства в очереди.Авторы ждут, чтобы определить, когда им разрешено помещать элемент в очередь.

Вы часто используете семафор мьютекса в сочетании с тем, чтобы убедиться, что только один поток изменяет саму очередь в любой данный моментвремя.

Например, вот код для очереди фиксированного размера, использующей семафоры с подсчетом 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
...