Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.84/25: Рейтинг темы: голосов - 25, средняя оценка - 4.84
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538

Асинхронность и Семафор

03.04.2021, 20:27. Показов 5636. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
здесь как-то затронули тему...
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
// Семафор надо блокировать в функции потока - в async, а не снаружи
// sem_wait блокирует семафор, sem_post - разблокирует. В таком порядке они и должны вызываться.
// Кроме того, эта пара функций должна вызываться в одном потоке.
логика:
If the value is 0, then we will wait till somebody has done sem_post
корректный код c async в пуле потоков (задаётся здесь вектором), наверно, выглядит так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <semaphore.h>
#include <future>
#include <thread>
#include <vector>
#include <Windows.h>
 
using namespace std;
 
int main(int argc, const char *argv[])
{
    std::vector<std::future<void>> futures;
    sem_t semaphore1;
    
    sem_init(&semaphore1, 0, 1);    // 1 - бинарный семафор (can have 0 or 1)
    for (int i = 0; i < 10; ++i) { 
        futures.push_back(std::async(launch::async, [&semaphore1, i]
        {   
            Sleep(1000);       
            
            sem_wait(&semaphore1);  // decrements the semaphore, if 0 - then blocking sem.
            Sleep(100);
         
            cout <<"Hello world " << i << endl; 
              
            sem_post(&semaphore1);          // increments the semaphore that is being waited => smbd becomes awakened
        }));  
 
    }    
 
    for (auto &fut : futures) {
        fut.get();
        
    }
    
    sem_destroy(&semaphore1);
    return 0;
}
корректно ли так писать?
что-то из источников складывается ощущение - что у каждого потока должен быть свой семафор?... в отличие от condition variable... верно ли моё ощущение?.. и тогда код, предоставленный, может не совсем корректен?

Добавлено через 41 минуту
p.s.
сделаю оговорку:

хоть бинарный семафор и мьютекс часто используют для одинаковой цели - для синхронизации, но механизм работы у них разный: мьютекс блокирует, семафор сигнализирует... поэтому 1й используется для доступа к разделяемым переменным, а второй в отношениях producer-consumer (writer-reader) между потоками...
в данном случае - разделяемый доступ к std::cout...
- может, правильнее делать 2 семафора (для writer и для reader) - как здесь... механизм вкратце здесь
важно:
операция «проверка и уменьшение» должна быть атомарной по отношению к другим потокам
p.p.s
в c++11 semaphore не вошёл, как и в boost, потому что разработчики предпочли mutex и condition_variable. поскольку работа семафора нестабильна... (пишу, как помню, - источник не найду сейчас)... наверно, по стандартной причине для сигнализирующих инструментов - spurious_wakeups:
Возврат из функции sem_wait может произойти преждевременно, если будет получен сигнал. При этом возвращается ошибка с кодом EINTR.
Разница между sem_wait и sem_trywait заключается в том, что последняя не приостанавливает выполнение процесса, если значение семафора равно нулю, а просто немедленно возвращает ошибку EAGAIN.
но всё-таки, раз condition_variables работают только с win7, а semaphore и на более ранних версиях win - думаю, стоит знать и этот инструмент сигнализации между потоками...
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
03.04.2021, 20:27
Ответы с готовыми решениями:

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

Семафор в ОС
Зачем нужно максимальное и начальное значения в создании семафора hSemaphore = CreateSemaphore( NULL, 1, 1, NULL ); Нужен пример где в ОС...

Семафор
самый распространенный конструктор класса Semaphore это : public Semaphore(int initialCount, int maximumCount) где initialCount...

34
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
05.04.2021, 10:59  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Сейчас вроде появился std::jthread
видела, не довелось познакомиться... сейчас нет msys2 32x, чтобы gcc/mingw c++20 32x потянуть оттуда... не знаю, как установить... сижу на c++17, установленного из msys2 год назад (gcc 9.3, даже не 10.0)

Добавлено через 34 минуты
Цитата Сообщение от JeyCi Посмотреть сообщение
std::vector<std::future<void>> futures;

Indeed, a std::vector will move its contents in memory if it grows.

I was surprised that I wasn't getting any data from the first consumer. After a lot of debugging, I finally realized that the vector moved in order to grow in size. Therefore, it seems that passing a movable object by reference is dangerous. What's the best way to solve that?
However, there are other container classes that you can use that do guarantee that elements already in the container will keep their address, even if it needs to allocate more memory. Amongst them are std::list and std::deque. There are also container adapter classes such as std::queue that by default use a std::deque for storage, and thus inherit its properties.
я, конечно, понимаю, что в данном случае речь шла о producer_consumer тестировании на базе thread_safe контейнера... но
Цитата Сообщение от JeyCi Посмотреть сообщение
и packaged_tasks, которые позволяют бросать исключения... или их можно std::move в др. поток, если надо...
- этих тоже вероятно касается... - чтобы не потерять их в памяти.... использовать queue... но ведь и std::vector<std::future<void>> при более сложной архитектуре проекта тоже, наверно, может столкнуться с проблемой вектора? (при move туда фьючей)?
0
19500 / 10105 / 2461
Регистрация: 30.01.2014
Сообщений: 17,818
05.04.2021, 14:03
JeyCi, проблема из вашей цитаты (кстати, почему не приводите ссылку на первоисточник?) - это не проблема вектора, а проблема кривых рук автора, как бы грубо это не звучало. Если мы передаем нечто по ссылке, и при передаче по ссылке это нечто потенциально может изменить свое состояние (в частности, может быть перемещено), то при выполнении в конкурентной среде у нас всегда будет гонка за это состояние. Независимо от того, вектор у нас или очередь, или еще что.
Глобально же проблема автора именно в том (и на это ему указали в ответах), что у него слишком много состояний. Он написал неоправданно сложный код, в котором запутался и потерял контроль над происходящим.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
05.04.2021, 19:04  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
ссылку на первоисточник?) - это не проблема вектора, а проблема кривых рук автора, как бы грубо это не звучало.
ссылка
https://codereview__stackexchange__com__/questions/247483/blocking-queue-in-c-using-semaphores
боюсь порежут

Цитата Сообщение от DrOffset Посмотреть сообщение
потерял контроль над происходящим.
возможно, логично, спасибо
Indeed, a std::vector will move its contents in memory if it grows
наверно, даже при move можно сохранить контроль... но в млучае вектора - как? - помещать в вектор unique_ptr'ы? или др контейнеры?... просто там очень несколько кодов - с ходу не могу уловить ошибку и разобраться...
думаю, ваша правда в захвате в люмбду [this]... возможно, действительно, лучше в его случае [*this]?.. ?или неправильная передача функции в поток
C++
1
std::thread consumerThread (Consumer(bq, 0));
лучше бы обернуть в std::ref?
- возможно, тут и теряет контроль...
мне надо сильно потестить те коды, чтобы разобраться... разберусь ли?... но если вы своим Pro взглядом увидите bug - черканите please
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
05.04.2021, 19:33
Цитата Сообщение от JeyCi Посмотреть сообщение
думаю, ваша правда в захвате в люмбду [this]... возможно, действительно, лучше в его случае [*this]?
[*this] точно не надо, это будет копия текущего объекта.
Здесь надо следить за временем жизни объектов, которые ты передаёшь в поток, и понимать, что именно ты передаёшь по ссылке, а что по значению.
Цитата Сообщение от JeyCi Посмотреть сообщение
лучше бы обернуть в std::ref?
Что ты там собралась обёртывать?

Добавлено через 3 минуты
Если ты передаёшь в поток что-то по ссылке или по указателю, то необходимо гарантировать, что поток завершиться раньше, чем будет уничтожен объект, на который ты ссылаешься.
1
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
05.04.2021, 19:48
Цитата Сообщение от JeyCi Посмотреть сообщение
наверно, даже при move можно сохранить контроль... но в млучае вектора - как? - помещать в вектор unique_ptr'ы? или др контейнеры?... просто там очень несколько кодов - с ходу не могу уловить ошибку и разобраться...
Суть в том, что автор захотел сделать раздельную блокировку для записи и для чтения очереди.
Только выбрал для этого стандартный контейнер(да ещё и вектор, которому не "запретил" реаллокацию).
Сделать такую очередь на базе стандартных контейнеров/адапторов не получится(без идиотизма).
Хотя не сложно написать такую очередь(с раздельной блокировкой для "хвоста" и "головы") самостоятельно.
Очереди на базе стандартных контейнеров должны полностью блокироваться на время любых операции, а для снижения времени блокировки и повышении безопасности по исключениям разумно использовать unique_ptr'ы(как вы заметили), если объекты не поддерживают noexcept move семантику.
Всё остальное, что вы написали - не относится к проблемам того кода.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
05.04.2021, 19:50  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Что ты там собралась обёртывать?
C++
1
2
a=Consumer(bq, 0);
std::thread(threadFunction, std::ref(a);
типа такого... вообще как-то странно передаёт (ещё не вчиталась, может функция в классе Consumer)
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
05.04.2021, 20:08
Цитата Сообщение от zayats80888 Посмотреть сообщение
Только выбрал для этого стандартный контейнер(да ещё и вектор, которому не "запретил" реаллокацию).
Хотя нет, очередь там константного размера, автор как раз в курсе про реаллокацию. Там нет блокировки для output queue у Consumer и слишком "навороченная" блокировка очереди обмена(я в неё особо не вникал).

Цитата Сообщение от JeyCi Посмотреть сообщение
типа такого...
В этом нет никакого смысла(скорее лишние проблемы). Consumer сам является функтором и при перемещении thread ничего не сломается(функтор "останется на месте").
На сами объекты thread тоже никто не ссылается.
1
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
06.04.2021, 10:10  [ТС]
Цитата Сообщение от JeyCi Посмотреть сообщение
столкнуться с проблемой вектора
действительно, в многопоточности в норм. коде и проблем с вектором не возникает (тема: Многопоточное заполнение вектора векторов) и асинхронность нормально задействуется...

Добавлено через 2 часа 16 минут
несколько remarkable_things для async:
1) рекурсивный запуск асинхр. потоков
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// http://man.hubwiz.com/docset/C.docset/Contents/Resources/Documents/output/en/cpp/thread/async.html
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
 
template <typename RAIter>
int parallel_sum(RAIter beg, RAIter end)
{
    auto len = end - beg;
    if(len < 1000)
        return std::accumulate(beg, end, 0);
 
    RAIter mid = beg + len/2;
    auto handle = std::async(std::launch::async,
                              parallel_sum<RAIter>, mid, end);
    int sum = parallel_sum(beg, mid);
    return sum + handle.get();
}
 
int main()
{
    std::vector<int> v(10000, 1);
    std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n';
}
2) (note that the destructors of std::futures obtained by means other than a call to std::async never block)
3) зацикливание отлова результата работы потоков, чтобы не блокировать код (хорошие объяснения на U++)
4) отлов исключений
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// https://eli.thegreenplace.net/2016/the-promises-and-challenges-of-stdasync-task-based-parallelism-in-c11/
int accumulate_block_worker_ret(int* data, size_t count) {
  throw std::runtime_error("something broke");
  return std::accumulate(data, data + count, 0);
}
 
...
 
{
  // Usage.
  std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8};
  try {
    std::future<int> fut = std::async(
        std::launch::async, accumulate_block_worker_ret, v.data(), v.size());
    std::cout << "use_worker_in_std_async computed " << fut.get() << "\n";
  } catch (const std::runtime_error& error) {
    std::cout << "caught an error: " << error.what() << "\n";
  }
}
5)
std::launch::async enable asynchronous evaluation
std::launch::deferred enable lazy evaluation
6) для U++ есть такой класс
LazyUpdate (this one is .. invention and is important everywhere mutable evaluation caches are used...
7) ... а тут я начинала знакомство с async с accumulate

Добавлено через 1 минуту
ИТОГО:
Основные вопросы, возникающие при старте знакомства с async и MT:
- обходу блокировки при возвращениИ результата из fut.get() (что впрочем справедливо и для thread.join())
- выбросу исключений в основной поток, если что-то пойдёт не так
***
... всё-таки остаётся последний вопрос:
раз cout и cerr у нас в разных потоках всегда в C/C++ -- не потеряю ли я чего (бросая не понятно куда исключения и результаты) -- в общем, нужен ли какой специальный hint (чтобы бросать и туда, и туда)... или синхронизации с cout И try{} catch(...){} для отлова исключений достаточно?
сама отвечу: - думаю, что достаточно... лучше в run-time
(чуть что поправят)

Добавлено через 29 минут
P.S.
jthread (C++20) std::thread with support for auto-joining and cancellation
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
06.04.2021, 19:20  [ТС]
механика работы async
std::async() does following things,​
◾It automatically creates a thread (Or picks from internal thread pool) and a promise object for us.
◾Then passes the std:: promise object to thread function and returns the associated std::future object.
◾When our passed argument function exits then its value will be set in this promise object, so eventually return value will be available in std::future object.
p.s.
using std:: packaged_task - return value or exception thrown is stored in a shared state which can be accessed through std::future objects
Добавлено через 5 минут
p.p.s.
1.Prefer std::async to std::thread. Futures are just too useful to ignore; especially if your code deals with exception handling, this is the only sane way to stay safe. Results provided by different threads should be wrapped in futures.
2.Always use the std::launch::async policy with std::async if you actually want multi-threading. Do not rely on the default policy. Do not use deferred unless you have very special needs. Remember that deferred is just syntactic sugar over holding a function pointer to call it later.
3.If you need a real thread pool or some other higher-level concurrency construct, use a library or roll your own. Standard objects like std::future, std:: promise and std:: packaged_task can be very helpful.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
10.04.2021, 16:21  [ТС]
Цитата Сообщение от JeyCi Посмотреть сообщение
в данном случае - разделяемый доступ к std::cout...
- прямо из 1-го поста
а встретился совет:
There is no need to lock in print(). Single calls to member functions of iostreams are atomic
да и быстрее print(), чем cout....
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
10.04.2021, 16:22
Цитата Сообщение от JeyCi Посмотреть сообщение
да и быстрее print(), чем cout....
Разве?
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
10.04.2021, 19:25  [ТС]
чем просто cout - ДА (п.4 и п.8)
Однако все равно можно использовать cin / cout и достичь той же скорости, что и scanf / printf, включив следующие две строки в функцию main ():
C++
1
2
3
4
 #include <bits/stdc++.h>
...
ios_base::sync_with_stdio(false);
cin.tie(NULL);
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    return 0;
}
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
22.04.2021, 21:15  [ТС]
P.S.
касательно сигнальных механизмов IPC (в частности семафора)
Важно также, что сигнал может быть послан из обработчика прерываний, и не является блокирующей операцией, поэтому часто используется в ОС реального времени.
-- всё сводится к reentrancy функции ... ...
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
26.04.2021, 21:18  [ТС]
Цитата Сообщение от JeyCi Посмотреть сообщение
- выбросу исключений в основной поток, если что-то пойдёт не так
Thread Synchronization with Condition Variables or Tasks
So there are a lot of reasons to prefer tasks to condition variables.
0
263 / 152 / 33
Регистрация: 29.06.2019
Сообщений: 1,538
22.05.2021, 07:46  [ТС]
Цитата Сообщение от JeyCi Посмотреть сообщение
(gcc 9.3, даже не 10.0)
есть и •GCC 11.1 - WinLibs standalone build of GCC and MinGW-w64 for Windows -ещё не проверяла...
p.s.
если доберусь до разработки на Linux: Lib32gcc-10-dev-x32-cross Download for Linux (deb)

Добавлено через 8 минут
Debian vs Ubuntu

Добавлено через 23 минуты
topic "Установил Linux, как установить Qt" - здесь советуют Fedora (Red Hat) - рус.яз.
Red Hat Enterprise Linux (платная)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
22.05.2021, 07:46
Помогаю со студенческими работами здесь

Семафор
В парикмахерской расположено единственное кресло, на котором спит парикмахер, и несколько стульев для клиентов. Когда клиент приходит в...

[C++] семафор
Рассмотрим взаимодействие двух потоков, один из которых пишет данные в буферный пул, а другой считывает их из пула. Буферный пул состоит из...

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

Семафор
Задача производителей и потребителей. Есть 3 программы: менеджер, производитель и потребитель. Менеджер запускает производителей...

Семафор
Написать программу, создающую дочерний процесс. Родительский процесс создаёт семафор (сем1) и общий файл. Дочерний процесс записывает в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Уведомление о неверно выбранном значении справочника
Maks 06.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "НарядПутевка", разработанного в конфигурации КА2. Задача: уведомлять пользователя, если в документе выбран неверный склад. . .
Установка Qt Creator для C и C++: ставим среду, CMake и MinGW без фреймворка Qt
8Observer8 05.04.2026
Среду разработки Qt Creator можно установить без фреймворка Qt. Есть отдельный репозиторий для этой среды: https:/ / github. com/ qt-creator/ qt-creator, где можно скачать установщик, на вкладке Releases:. . .
AkelPad-скрипты, структуры, и немного лирики..
testuser2 05.04.2026
Такая программа, как AkelPad существует уже давно, и также давно существуют скрипты под нее. Тем не менее, прога живет, периодически что-то не спеша дополняется, улучшается. Что меня в первую очередь. . .
Отображение реквизитов в документе по условию и контроль их заполнения
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеСпецтехники", разработанного в конфигурации КА2. Данный документ берёт данные из другого нетипового документа. . .
Фото всей Земли с борта корабля Orion миссии Artemis II
kumehtar 04.04.2026
Это первое подобное фото сделанное человеком за 50 лет. Снимок называют новым вариантом легендарной фотографии «The Blue Marble» 1972 года, сделанной с борта корабля «Аполлон-17». Новое фото. . .
Вывод диалогового окна перед закрытием, если документ не проведён
Maks 04.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: реализовать программный контроль на предмет проведения документа. . .
Программный контроль заполнения реквизитов табличной части документа
Maks 02.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "СписаниеМатериалов", разработанного в конфигурации КА2. Задача: 1. Реализовать контроль заполнения реквизита. . .
wmic не является внутренней или внешней командой
Maks 02.04.2026
Решение: DISM / Online / Add-Capability / CapabilityName:WMIC~~~~ Отсюда: https:/ / winitpro. ru/ index. php/ 2025/ 02/ 14/ komanda-wmic-ne-naydena/
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru