Что такое семафор?

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

Что такое семафор и как вы его используете?

Ответ 1

Подумайте о семафорах как вышибалы в ночном клубе. Есть определенное количество людей, которые разрешены в клубе сразу. Если клуб заполнен, никто не может войти, но как только один человек уйдет из другого человека, он может войти.

Это просто способ ограничить количество потребителей определенным ресурсом. Например, чтобы ограничить количество одновременных вызовов в базе данных в приложении.

Вот очень педагогический пример в С#: -)

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TheNightclub
{
    public class Program
    {
        public static Semaphore Bouncer { get; set; }

        public static void Main(string[] args)
        {
            // Create the semaphore with 3 slots, where 3 are available.
            Bouncer = new Semaphore(3, 3);

            // Open the nightclub.
            OpenNightclub();
        }

        public static void OpenNightclub()
        {
            for (int i = 1; i <= 50; i++)
            {
                // Let each guest enter on an own thread.
                Thread thread = new Thread(new ParameterizedThreadStart(Guest));
                thread.Start(i);
            }
        }

        public static void Guest(object args)
        {
            // Wait to enter the nightclub (a semaphore to be released).
            Console.WriteLine("Guest {0} is waiting to entering nightclub.", args);
            Bouncer.WaitOne();          

            // Do some dancing.
            Console.WriteLine("Guest {0} is doing some dancing.", args);
            Thread.Sleep(500);

            // Let one guest out (release one semaphore).
            Console.WriteLine("Guest {0} is leaving the nightclub.", args);
            Bouncer.Release(1);
        }
    }
}

Ответ 2

Статья Мьютексы и семафоры, демистифицированные Майклом Барром - отличное краткое введение в то, что делает мьютексы и семафоры разными, и когда они должны и должны не используется. Здесь я привел несколько ключевых параграфов.

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

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

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

...

В этот момент интересная аналогия делается с использованием идеи ключей для ванной, как защита общих ресурсов - ванной комнаты. Если в магазине есть отдельная ванная комната, тогда одного ключа будет достаточно для защиты этого ресурса и предотвращения одновременного использования несколькими людьми.

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

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

...

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

...

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

...

Причиной широко распространенной современной путаницы между мьютексами и семафорами является историческая история, поскольку она восходит к изобретательству 1974 года Семафора (столица "S" в этой статье) Джикстра. До этой даты ни один из механизмов синхронизации и сигнализации прерываний, известных ученым-вычислителям, не был эффективно масштабирован для использования более чем двумя задачами. Редкий, безопасный и масштабируемый сейсморазведчик Dijkstra был применен как для защиты критических секций, так и для сигнализации. И вот началось смятение.

Однако позже стало очевидным для разработчиков операционной системы после появления приоритетной ОСРВ на основе приоритета (например, VRTX, около 1980 г.), публикации научных статей, устанавливающих RMA, и проблем, вызванных инверсией приоритета, и документ о приоритетных протоколах наследования в 1990 году 3, стало очевидно, что мьютексы должны быть больше, чем просто семафоры с двоичным счетчиком.

Mutex: совместное использование ресурсов

Семафор: сигнализация

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

Ответ 3

Mutex: доступ эксклюзивного члена к ресурсу

Семафор: доступ к ресурсу n-член

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

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

Ответ 4

@Craig:

Семафор - это способ блокировки ресурса, чтобы гарантировать, что в то время как часть кода выполняется, только этот кусок кода имеет доступ к этот ресурс. Это поддерживает два потока от одновременного доступа к ресурсу, что может вызвать проблемы.

Это не ограничивается только одним потоком. Семафор может быть сконфигурирован так, чтобы разрешить фиксированное число потоков доступа к ресурсу.

Ответ 5

Рассмотрим такси, которое может вместить в общей сложности 3 (сзади) +2 (передних) человека, включая водителя. Таким образом, semaphore позволяет в салоне автомобиля одновременно находиться не более 5 человек. А mutex допускает размещение только одного человека на одном сиденье автомобиля.

Следовательно, Mutex должен разрешать монопольный доступ к ресурсу (например, потоку ОС), в то время как Semaphore должен разрешать доступ для n числа ресурсы за один раз.

Ответ 6

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

Здесь семафор не используется как механизм исключения, а как механизм сигнализации. На семафоре ожидание задачи Задача продления - размещение на семафоре.

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

Ответ 7

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

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

Семафор имеет две части: счетчик и список задач, ожидающих доступа к определенному ресурсу. Семафор выполняет две операции: 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 потоков входят (через счетный семафор) и пытаются использовать первый экземпляр?

Ответ 8

Семафор - это объект, содержащий натуральное число (т.е. целое число, большее или равное нулю), на котором определены две изменяющиеся операции. Одна операция, V, добавляет 1 к естественному. Другая операция P уменьшает натуральное число на 1. Оба действия являются атомарными (т.е. Никакая другая операция не может выполняться одновременно с V или P).

Поскольку натуральное число 0 не может быть уменьшено, вызов P в семафоре, содержащем 0, блокирует выполнение вызывающего процесса (/thread) до момента, когда число больше не равно 0 и P может быть успешно (и атомарно) выполнено.

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

Ответ 9

Я создал визуализацию, которая должна помочь понять идею. Семафор контролирует доступ к общему ресурсу в многопоточной среде. enter image description here

ExecutorService executor = Executors.newFixedThreadPool(6);

Semaphore semaphore = new Semaphore(4);

Runnable longRunningTask = () -> {
    boolean permit = false;
    try {
        permit = semaphore.tryAcquire(1, TimeUnit.SECONDS);
        if (permit) {
            System.out.println("Semaphore acquired");
            Thread.sleep(5);
        } else {
            System.out.println("Could not acquire semaphore");
        }
    } catch (InterruptedException e) {
        throw new IllegalStateException(e);
    } finally {
        if (permit) {
            semaphore.release();
        }
    }
};

// execute tasks
for (int j = 0; j < 10; j++) {
    executor.submit(longRunningTask);
}
executor.shutdown();

Выход

Semaphore acquired
Semaphore acquired
Semaphore acquired
Semaphore acquired
Could not acquire semaphore
Could not acquire semaphore

Пример кода из статьи article

Ответ 10

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

Ответ 11

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

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

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

Ознакомьтесь с лекциями в http://www.cs.columbia.edu/~jae/4118/lect/L05-ipc.html.

Ответ 12

В программировании, особенно в системах Unix, семафоры - это метод для координации или синхронизации действий, в которых несколько процессов конкурируют за одни и те же ресурсы операционной системы.

Семафор - это значение в определенном месте в хранилище операционной системы, которое каждый процесс может проверить, а затем изменить. В зависимости от найденного значения процесс может использовать ресурс или понимать, что он уже используется, и ждать некоторого периода, прежде чем повторять попытку.

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

Семафоры обычно используются для двух целей: 1) Совместное использование общего пространства памяти 2) Чтобы предоставить доступ к файлам.

Семафоры являются одним из методов межпроцессного взаимодействия (IPC).

Язык программирования C предоставляет набор интерфейсов или "функций" для управления семафорами.

Ответ 13

Семафоры действуют как ограничители потоков.

Пример: Если у вас есть пул из 100 потоков, и вы хотите выполнить какую-либо операцию с БД. Если 100 потоков обращаются к БД в определенный момент времени, то в БД может возникнуть проблема с блокировкой, поэтому мы можем использовать семафор, который допускает только ограниченный поток за один раз. В следующем примере разрешен только один поток за один раз. Когда поток вызывает метод acquire(), он получает доступ и после вызова метода release() освобождает доступ, так что следующий поток получит доступ.

    package practice;
    import java.util.concurrent.Semaphore;

    public class SemaphoreExample {
        public static void main(String[] args) {
            Semaphore s = new Semaphore(1);
            semaphoreTask s1 = new semaphoreTask(s);
            semaphoreTask s2 = new semaphoreTask(s);
            semaphoreTask s3 = new semaphoreTask(s);
            semaphoreTask s4 = new semaphoreTask(s);
            semaphoreTask s5 = new semaphoreTask(s);
            s1.start();
            s2.start();
            s3.start();
            s4.start();
            s5.start();
        }
    }

    class semaphoreTask extends Thread {
        Semaphore s;
        public semaphoreTask(Semaphore s) {
            this.s = s;
        }
        @Override
        public void run() {
            try {
                s.acquire();
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+" Going to perform some operation");
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } 
    }

Ответ 14

Это старый вопрос, но одно из наиболее интересных применений семафора - это блокировка чтения/записи, и это явно не упоминалось.

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

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

Далее читать:

Ответ 15

Вот еще несколько интересных сведений о семафоре:

Семафоры представляют собой конструкцию программирования, разработанную Э. В. Дейкстре в конце 1960-х годов. Модель Дейкстры - это работа железных дорог: рассмотрим участок железной дороги, в котором есть единственный след, по которому допускается только один поезд за раз.

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

В компьютерной версии семафор представляется простым целым числом. Поток ждет разрешения для продолжения, а затем сообщает, что он выполнил операцию P на семафоре.

Семантика операции такова, что поток должен ждать, пока значение семафора не будет положительным, а затем измените значение семафора, вычитая из него значение. Когда он будет завершен, поток выполняет операцию V, которая изменяет значение семафора, добавляя к ней один. Крайне важно, чтобы эти операции происходили атомарно - их нельзя разделить на куски, между которыми могут происходить другие действия на семафоре. В операции P значение семафора должно быть положительным только до того, как оно уменьшится (в результате получится значение, которое гарантировано неотрицательно и одно меньше, чем оно было до того, как оно уменьшилось).

В обоих операциях P и V арифметика должна выполняться без помех. Если две операции V выполняются одновременно на одном и том же семафоре, чистый эффект должен быть таким, что новое значение семафора на два больше, чем было.

Мнемоническое значение P и V непонятно большинству мира, так как Дейкстра - голландский. Тем не менее, в интересах настоящей стипендии: P означает пролаген, составленное слово, полученное из proberen te verlagen, что означает попытку уменьшить. V означает verhogen, что означает увеличение. Это обсуждается в одной из технических заметок Дейкстры, EWD 74.

sem_wait (3RT) и sem_post (3RT) соответствуют операциям Dijkstra P и V. sem_trywait (3RT) является условной формой операции P: если вызывающий поток не может уменьшить значение семафора без ожидания, вызов немедленно возвращается с ненулевым значением.

Существует два основных типа семафоров: двоичные семафоры, которые никогда не принимают значения, отличные от нуля или единицы, и подсчет семафоров, которые могут принимать произвольные неотрицательные значения. Бинарный семафор логически похож на мьютекс.

Однако, хотя он не применяется, мьютексы должны быть разблокированы только потоком, удерживающим блокировку. Не существует понятия "поток, содержащий семафор", поэтому любой поток может выполнять операцию V (или sem_post (3RT)).

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

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

Ответ 16

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