Разница между подсчетами и двоичными семафорами

В чем разница между подсчетом и двоичным семафором.

То, что я где-то видел, - это то, что оба могут контролировать N количество процессов, которые запрашивали ресурс. Оба взяли и освободили состояния.

Есть ли ограничение на количество ресурсов, которые может защитить двоичный семафор и счетный семафор?

Оба позволяют только одному процессу использовать ресурс за раз...

Есть ли другая разница? Правильны ли указанные выше свойства?

Ответ 1

Фактически оба типа используются для синхронизации доступа к совместно используемому ресурсу, независимо от того, является ли объект, который пытается получить доступ, процессом или даже потоком.

Разница заключается в следующем:

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

С другой стороны, подсчет семафоров принимает более двух значений, они могут иметь любое значение, которое вы хотите. Максимальное значение X, которое они принимают, позволяет X process/threads одновременно обращаться к совместно используемому ресурсу.

Для получения дополнительной информации ознакомьтесь с этой ссылкой.
http://www.chibios.org/dokuwiki/doku.php?id=chibios:articles:semaphores_mutexes

ИЗМЕНИТЬ
Максимальное значение, которое может принимать счетный семафор, - это количество процессов, которые вы хотите разрешить в критический раздел в одно и то же время.
Опять же, у вас может быть случай, когда вы хотите исключить определенный ресурс, но вы знаете, что к этому ресурсу может быть обращено максимальное количество процессов (скажем, X), поэтому вы устанавливаете счетный семафор со значением X.

Это позволит процессам X получать доступ к этому ресурсу одновременно; но процесс X + 1 должен будет дождаться выхода одного из процессов в критическом разделе.

Ответ 2

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

Семафор имеет две части: счетчик и список задач, ожидающих доступа к определенному ресурсу. Семафор выполняет две операции: wait (P) [это как получение блокировки] и release (V) [аналогично освобождению блокировки] - это единственные две операции, которые можно выполнять на семафоре. В двоичном семафоре счетчик логически находится между 0 и 1. Вы можете думать, что он похож на блокировку с двумя значениями: open/closed. Счетный семафор имеет несколько значений для подсчета.

Важно понимать, что семафорный счетчик отслеживает количество задач, которые не нужно блокировать, т.е. они могут добиться прогресса. Задачи и добавьте себя в список семафоров только тогда, когда счетчик равен нулю. Поэтому задача добавляется в список в подпрограмме P(), если она не может прогрессировать и "освобождается" с помощью процедуры V().

Теперь довольно очевидно увидеть, как бинарные семафоры могут использоваться для решения синхронизации и взаимного исключения - они по сути являются блокировками.

ех. Синхронизация:

thread A{
semaphore &s; //locks/semaphores are passed by reference! think about why this is so.
A(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
;// some block of code B2
...
}

//thread B{
semaphore &s;
B(semaphore &s): s(s){} //constructor
foo(){
...
...
// some block of code B1
s.V();
..
}

main(){
semaphore s(0); // we start the semaphore at 0 (closed)
A a(s);
B b(s);
}

В приведенном выше примере B2 может выполняться только после завершения выполнения B1. Пусть говорят, что поток A приходит первым - переходит в sem.P() и ждет, так как счетчик равен 0 (закрытый). Thread B входит, заканчивает B1, а затем освобождает нить A, которая затем завершает B2. Таким образом, мы достигаем синхронизации.

Теперь посмотрим на взаимное исключение с двоичным семафором:

thread mutual_ex{
semaphore &s;
mutual_ex(semaphore &s): s(s){} //constructor
foo(){
...
s.P();
//critical section
s.V();
...
...
s.P();
//critical section
s.V();
...

}

main(){
semaphore s(1);
mutual_ex m1(s);
mutual_ex m2(s);
}

Взаимное исключение довольно просто: m1 и m2 не могут одновременно войти в критический раздел. Поэтому каждый поток использует один и тот же семафор для обеспечения взаимного исключения для двух критических разделов. Теперь, возможно ли иметь больше concurrency? Зависит от критических секций. (Подумайте, как еще можно использовать семафоры для достижения взаимного исключения.. подсказка: мне обязательно нужно использовать только один семафор?)

Подсчет семафора: семафор с несколькими значениями. Давайте посмотрим, что это означает: замок с более чем одним значением? Так что открытые, закрытые и... хм. Какая польза от многоступенчатой ​​блокировки во взаимном исключении или синхронизации?

Пусть проще:

Синхронизация с использованием счетного семафора: Скажем, у вас есть 3 задачи - №1 и 2, которые вы хотите выполнить после 3. Как вы планируете синхронизацию?

thread t1{
...
s.P();
//block of code B1

thread t2{
...
s.P();
//block of code B2

thread t3{
...
//block of code B3
s.V();
s.V();
}

Итак, если ваш семафор начинает закрываться, вы гарантируете, что t1 и t2 блокируются, добавляются в список семафоров. Затем идет все важные t3, завершает свой бизнес и освобождает t1 и t2. Какой порядок они освобождают? Зависит от реализации списка семафоров. Может быть FIFO, может быть определен определенный приоритет и т.д. (Примечание: подумайте о том, как бы вы упорядочили свои P и V, если бы вы хотели, чтобы t1 и t2 выполнялись в определенном порядке, и если вы не знали о реализации семафора)

(Узнайте: что произойдет, если число V больше числа P?)

Взаимное исключение Использование подсчета семафоров: я хотел бы, чтобы вы построили свой собственный псевдокод для этого (заставляет вас лучше понимать ситуацию!), но фундаментальная концепция такова: счетный семафор счетчика = N позволяет N задачам вводить критический разрез. Это означает, что у вас есть N задач (или потоков, если хотите), введите критический раздел, но N + 1-я задача блокируется (идет по нашему списку избранных заблокированных задач), и только пропускается, когда кто-то V семафор Хотя бы один раз. Таким образом, счетчик семафора вместо качания между 0 и 1 теперь находится между 0 и N, позволяя N задачам свободно входить и выходить, никого не блокируя!

Теперь, зачем тебе нужен такой странный замок? Разве не весь смысл взаимного исключения не позволяет более чем одному парню получить доступ к ресурсу? Думать. (Подсказка... У вас не всегда есть только один диск на вашем компьютере, вы...?)

Подумать: есть ли взаимное исключение, имея только счетный семафор? Что делать, если у вас есть 10 экземпляров ресурса и 10 потоков входят (через счетный семафор) и пытаются использовать первый экземпляр?

Ответ 3

Самое основное отличие между подсчетом и двоичным семафором заключается в следующем:

  • Двоичный семафор не может обрабатывать ограничение Bounded как его просто переменную, которая имеет двоичное значение. Семафор подсчета. Он может обрабатывать ограниченное ожидание, поскольку он преобразовал переменную в структуру с очередью.
  • Выполнение Strcuture Двоичный семафор:  int s;

    Подсчет семафора:  Struct S  {     int s;     Очередь q;  }

Используя счетный семафор, теперь процесс, когда-то полученный CS (критический раздел), теперь должен ждать, пока другой получит CS, поэтому ни один процесс не будет страшным. Каждый процесс получает шанс для CS.