В какой ситуации Вы используете семафор по взаимному исключению в C++?

Всюду по ресурсам я читал о многопоточности, взаимное исключение чаще используется и обсуждается по сравнению с семафором. Мой вопрос состоит в том при использовании семафора по взаимному исключению? Я не вижу семафоры в потоке Повышения. Это означает, что семафоры больше не использовали много в эти дни?

Насколько я имею, понимают, семафоры позволяют ресурсу быть совместно использованным несколькими потоками. Это только возможно, если те потоки только читают ресурс, но не запись. Это корректно?

36
задан jasonline 1 March 2010 в 01:08
поделиться

8 ответов

Boost.Thread имеет мьютексы и условные переменные. Поэтому чисто с точки зрения функциональности семафоры избыточны [*], хотя я не знаю, почему они опущены.

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

Ресурсы чтения и записи - отвлекающий маневр, IMO не имеет ничего общего с разницей между мьютексом и семафором. Если вы используете подсчетный семафор, у вас может возникнуть ситуация, когда несколько потоков одновременно обращаются к одному и тому же ресурсу, и в этом случае, вероятно, должен быть доступ только для чтения. В этой ситуации вы можете вместо этого использовать shared_mutex из Boost.Thread. Но семафоры не «для» защиты ресурсов, как мьютексы, они «для» отправки сигнала от одного потока к другому. Их можно использовать для управления доступом к ресурсу.

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

[*] Вот примерно то, как вы реализуете семафор подсчета, используя мьютекс и переменную условия. Для реализации общего семафора, конечно, вам понадобится разделяемый мьютекс / условная переменная:

struct sem {
    mutex m;
    condvar cv;
    unsigned int count;
};

sem_init(s, value)
    mutex_init(s.m);
    condvar_init(s.cv);
    count = value;

sem_wait(s)
    mutex_lock(s.m);
    while (s.count <= 0) {
        condvar_wait(s.cv, s.m);
    }
    --s.count;
    mutex_unlock(s.m);

sem_post(s)
    mutex_lock(s.m);
    ++s.count;
    condvar_broadcast(s.cv)
    mutex_unlock(s.m);

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

4
ответ дан 27 November 2019 в 06:05
поделиться

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

Что касается семафора, подумайте о семафоре как о потребляющем ресурс, но не о фактическом владении им. Обычно это называют «пустым» семафором, а не тем, что он принадлежит потоку. Тогда особенность семафора состоит в том, что другой поток может «заполнить» семафор обратно до «полного» состояния.

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

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

11
ответ дан 27 November 2019 в 06:05
поделиться

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

Типичные приложения: Вы не хотите создавать более (например) 5 подключений к базе данных. Независимо от количества рабочих потоков, они должны использовать эти 5 подключений. Или, если вы работаете на N-ядерном компьютере, вы можете убедиться, что определенные задачи, интенсивно использующие ЦП / память, не выполняются более чем в N потоках одновременно (потому что это только снизит пропускную способность из-за переключения контекста. и эффекты перемалывания кеша). Возможно, вы даже захотите ограничить количество параллельных задач с интенсивным использованием ЦП / памяти до N-1, чтобы остальная часть системы не голодала. Или представьте, что для определенной задачи требуется много памяти, поэтому одновременный запуск более N экземпляров этой задачи приведет к подкачке страниц. Здесь вы можете использовать семафор, чтобы убедиться, что одновременно выполняется не более N экземпляров этой конкретной задачи.

РЕДАКТИРОВАТЬ / PS: Из вашего вопроса «Это возможно только в том случае, если эти потоки только читают ресурс, но не записывают. Это правильно?» и ваш комментарий, мне кажется, что вы думаете о ресурсе как о переменной или потоке, которые могут быть прочитаны или записаны, и которые могут быть записаны только одним потоком за раз. Не надо. В этом контексте это вводит в заблуждение.

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

23
ответ дан 27 November 2019 в 06:05
поделиться

Мне кажется, что нет простого способа ДЕЙСТВИТЕЛЬНО ответить на ваш вопрос, не игнорируя некоторую важную информацию о семафорах. Люди написали много книг о семафорах , поэтому любой ответ из одного или двух абзацев является медвежьей услугой. Популярная книга - Маленькая книга семафоров ... для тех, кто не любит большие книги :).

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

Обновление:
Дэн указал на некоторые ошибки в моих примерах, я оставлю это со ссылками, которые предлагают НАМНОГО лучшие объяснения, чем мои :).

Вот ссылки, показывающие ПРАВИЛЬНЫЕ способы использования семафоров:
1. Статья IBM
2. Лекция Чикагского университета
3. Первоначально опубликованная мною статья Netrino.
4. Бумага «продать билеты» + код.

3
ответ дан 27 November 2019 в 06:05
поделиться

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

Мьютексы сильно зависят от реализации. Они оптимизированы для целей двоичной блокировки. Обычный вариант использования мьютекса - это двоичный семафор.

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

-1
ответ дан 27 November 2019 в 06:05
поделиться

Насколько Я понимаю, что в наши дни термин «семафоры» сильно связан с IPC. Это по-прежнему означает, что защищенную переменную могут изменять многие процессы, но среди процессов эта функция поддерживается ОС.

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

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

0
ответ дан 27 November 2019 в 06:05
поделиться

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

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

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

9
ответ дан 27 November 2019 в 06:05
поделиться

Как взято из этой статьи :

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

Наконец, класс Semaphore.Допустим, у вас есть метод, который действительно сильно нагружает ЦП, а также использует ресурсы, к которым вам нужно контролировать доступ (с помощью мьютексов :)). Вы также определили, что максимум пять вызовов метода - это все, что ваша машина может обработать, не делая ее безответной. Лучшее решение здесь - использовать класс Semaphore, который позволяет ограничить доступ определенного количества потоков к ресурсу.

1
ответ дан 27 November 2019 в 06:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: