97 / 0 / 1
Регистрация: 01.07.2018
Сообщений: 25
|
|
1 | |
Синхронизация потоков с time_point28.05.2020, 12:08. Показов 2966. Ответов 41
Метки нет (Все метки)
В программе запускается два потока, первым-поток, ожидающий инструкций от пользователя( выводит строку, ожидает ввод, запускает соответствующую функцию-либо изменяет общий контейнер, либо выводит из него данные), вторым запускается поток, выводящий точно по time_point данные из общего контейнера. Как синхронизировать потоки? Приложение пока консольное, проблема в том, что второй поток должен всегда точно по времени выводить сообщения и если первый считает информацию слишком поздно( не успеет выполнить вывод до очередной временной точки), то вывод со второго потока не успеет сработать вовремя. Думаю использовать timed_mutex, блокировать второй поток точно по времени, а в первом использовать try_lock_until( time_point-chrono::milliseconds(500). Есть ли более оптимальный вариант?
0
|
28.05.2020, 12:08 | |
Ответы с готовыми решениями:
41
Как привести тип time_point<std::filesystem::__file_clock, [.]>к типу const time_point<std::chrono::_V2::system_clock Синхронизация потоков Синхронизация потоков Синхронизация потоков - C++ |
Комп_Оратор)
|
|
02.06.2020, 18:47 | 21 |
Это интересный вопрос. На мой взгляд тут всё дело в автоматическом захвате-освобождении мьютекса, а как ОС реализует слип это её вопрос. Важно что не спинлочит. А внешний цикл - да это цикл контроллера. Я же не однократное действо проворачиваю в задачах. Там конвейер (примитивны конечно).
Вообще интересный разговор. Буду думать. Добавлено через 2 минуты переменная, сон, конвейер. Запустите и посмотрите, что происходит. Последовательность действий задана строго. Другой вопрос, что не ясно когда весь рабочий процесс свернётся. Это зависит от копыта ударившего по клаве. Но так же и задумано. Иначе всё сложнее пришлось бы делать.
0
|
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
||||||
02.06.2020, 18:49 | 22 | |||||
wait с предикатом это всего лишь, не более того
Блокировка здесь ни при чём
0
|
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
|
|
02.06.2020, 18:51 | 23 |
Вы про планировщик задач ОС забыли.
Достаточно сделать её (continue_work) атомарной.
1
|
Комп_Оратор)
|
|
02.06.2020, 18:52 | 24 |
Наверно и так можно. Это хорошая идея и я подумаю. Важно, чтобы после окончания потока печати добавитель не затолкал в вектор что-то что уже не напечатается. То есть, надо сделать так, чтобы они вывалились в правильной последовательности. Печатающий должен быть последним)
0
|
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
02.06.2020, 18:53 | 25 |
0
|
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
|
|
02.06.2020, 18:55 | 26 |
Может в MSVS и достаточно, но стандарт не определяет store/load операции над volitilte переменными как атомарные.
0
|
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
|
|
02.06.2020, 18:57 | 27 |
Ну и что? Что здесь поменяется от того, что эта операция не будет атомарной, continue_work никогда не станет false?
1
|
Комп_Оратор)
|
|||||||||||
02.06.2020, 18:58 | 28 | ||||||||||
Опять вы не поняли.
Да пусть планировщик заснёт на пол секунды. Ну и что? Оба брата-акробата напихают больше огурцов. Но первый (единственный - точнее) получит новое значение continue_work именно печатающий. Он перекроет кислород заталкивающему перед нотификацией. Он подмутексом пишет переменную
0
|
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
|
|
02.06.2020, 19:08 | 29 |
Как я уже сказал
Добавлено через 6 минут Да нет, я понимаю как работает ваш код. Я говорю про две конкретные операции, запись и чтение continue_work, при чём тут continue_push?
0
|
Комп_Оратор)
|
|
02.06.2020, 19:14 | 30 |
zayats80888, похоже вы не хотите представить о чём речь идёт.
Ответьте на простой вопрос: изменение значения continue_work когда-нибудь отловится в потоке задачи печати (больше ни кто эту переменную не контролирует) ?Добавлено через 1 минуту Покажите их в коде и скажите какое это может иметь значение. Добавлено через 2 минуты Тогда кто и с кем тут может погоняться?
0
|
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
|
||||||
02.06.2020, 19:18 | 31 | |||||
Я уже дважды повторил, что с bool переменной, мне трудно представить нарушение инварианта.
Но у вас запись и чтение не атомарной переменной не синхронизированны! Я поясню так:
0
|
Комп_Оратор)
|
|
02.06.2020, 19:27 | 32 |
У меня булева перемнная. Это даже не char. Что касается гарантий, то глобальные переменные у потоков одного процесса общие. Поэтому, мне кажется, что вы повторяете некую формальную мантру.
Думаю, не стоит это продолжать, я почитаю ещё, конечно и найдя приличные примеры у того же Уильямса - покажу. Продолжение ни чего не даст, так как доказательств нет ни у одной из сторон.
0
|
Комп_Оратор)
|
|
02.06.2020, 20:09 | 34 |
Это же наш случай. Я это повторял много раз и ещё раз повторю. Вычисление с записью (если так удобно, пусть так) делается в main. Чтение производится циклически, и решение о остановке принимается после записи в main и ни как иначе. Порядок строго определён.
Добавлено через 46 секунд вот тута я говорил Добавлено через 14 минут там можно было бы задать данную переменную с клавиатуры, а не присваивать после ввода любого символа. Но с учётом замечания oleg-m1973, про volalile это не нужно)
0
|
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
|
|
02.06.2020, 20:18 | 35 |
Нет, посмотрите что такое memory_order
Добавлено через 7 минут Перечитайте 5 главу.
0
|
Комп_Оратор)
|
|
02.06.2020, 20:31 | 36 |
Я почитаю, конечно, но не понимаю как это может повлиять на последовательность операций в конкретно моём случае. Там разобраны разные вещи. в частности данные занимающие более одного байта и пр. Но почитаю. Пока что я не увидел тут сходных вещей кроме доказательства своей правоты. Порядок чтения и записи в моём случае железо-бетонный. Если я не прав, то тут слабое место, но я не могу себе это представить.
0
|
97 / 0 / 1
Регистрация: 01.07.2018
Сообщений: 25
|
|
03.06.2020, 09:26 [ТС] | 37 |
Я не могу использовать CV.wait() потому, что в функции, через которую юзер общается с программой, порядка 10 различных вопросов, которые программа ему задает. С CV.wait() проходит только 1 вопрос на 1 вывод таймпоинта первым потоком. Программа должна выводить вопросы юзеру до тех пор, пока до очередного таймпоинта не останется 5 секунд(чтобы успеть выполнить последний запрос), и если ввод данных попадает в эти последние 5 сек, то поток юзера засыпает до таймпоинт + 1 секунда(чтобы точно не помешать вовремя вывести напоминание).Пока самым оптимальным видится такой вариант, но постоянно на всех функциях, при попадании в эти 5 секунд, выдает такую ошибку "Вызвано исключение: нарушение доступа для чтения.
_Right_scary было nullptr." Причем, если не попадать в этот промежуток, все функции работают. void f(set<pair<chrono::system_clock::time_point, int64_t> >& TP, map<Store*, vector<shared_ptr<Store::Child > > >&Children) { set<pair<chrono::system_clock::time_point, int64_t> > ::iterator it; for (it = TP.begin(); it != TP.end(); it++) { Tp_Next = it->first+chrono::seconds(1); Tp_Try = it->first - chrono::seconds(5); time_t ON= std::chrono::system_clock::to_time_t(it->first); tm on; localtime_s(&on, &ON); int year1 = on.tm_year+1900, month=on.tm_mon+1, day=on.tm_mday; string S = ""; ostringstream sstr; sstr << year1<<month<<day; S=sstr.str(); map<Store*, vector<shared_ptr<Store::Child > > >::iterator it1; this_thread::sleep_until(it->first); unique_lock<mutex>UL1(MU); cout << endl << "TIME :" << endl; for (it1 = Children.begin(); it1 != Children.end(); it1++) { if (it1->first->Name == S) { it1->first->Get(it1->first->mp, it->second); } break; } } } void User_Request(map< Store*, vector<shared_ptr<Store::Child > > >& Children) { string Answer1, Answer, Object, Main_Object = ""; bool Bl = true; while ((chrono::system_clock::now()) <= Tp_End) { if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next ); } {unique_lock<mutex>UL1(MU); cout << "Do you need to work with the main objects' store or with its' substore?"; } cin >> Answer1; if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next ); } {unique_lock<mutex>UL1(MU); cout << "Enter the name"; } cin >> Object; if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next); } {unique_lock<mutex>UL1(MU); cout << "What do you need to do ? Enter get, update, show, query, range_query, remove"; } cin >> Answer; (Answer1.find("main") != -1) ? Bl = true : Bl = !Bl; shared_ptr<Store >Obj; shared_ptr<Store::Child> Obj1; Store* x = nullptr; ; map<Store*, vector<shared_ptr<Store::Child > > >::iterator it; if (Bl == true) { for (it = Children.begin(); it != Children.end(); it++) { if (it->first->Name == Object) { Obj.reset(x); break; } } } else { for (it = Children.begin(); it != Children.end(); it++) { for (auto it2 : it->second) { if (it2->Name == Object) { Obj1 = it2; break; } } } } string key, value; double a, b; int64_t ID = 0; if (Answer == "get") { if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next ); } {unique_lock<mutex>UL1(MU); cout << "Enter the ID"; } cin >> ID; if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next ); } {unique_lock<mutex>UL1(MU); (Bl == true) ? Obj->Get(Obj->mp, ID) : Obj1->Get(ID); } } else if (Answer == "update") { if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next ); } {unique_lock<mutex>UL1(MU); cout << "Enter the ID, key, value"; } cin >> ID >> key >> value; if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next); } {unique_lock<mutex>UL1(MU); (Bl == true) ? Obj->Update(ID, key, value) : Obj1->Update(ID, key, value); } } else if (Answer == "show") { if ((chrono::system_clock::now()) > Tp_Try) { this_thread::sleep_until(Tp_Next); } {unique_lock<mutex>UL1(MU); (Bl == true) ? Obj->Show(Obj->mp) : Obj1->Show(); } } } } Как это исправить? Добавлено через 1 час 54 минуты Может, кто знает, как вообще можно так потоки синхронизировать, чтобы напоминания по таймпонту всегда точно вовремя выводились, но и второй поток на юзера продолжал работать до последнего таймпоинта?
0
|
Комп_Оратор)
|
||||||
03.06.2020, 10:26 | 38 | |||||
Dgamilya, вы и тегами для кода не умеете пользоваться. Мы научим. Сначала попросим модераторов добавить вам теги.
А теперь смотрите на верхнюю линейку окна редактора, где набираете текст. Вторая позиция в среднем (2-м с верху/низу) ряду выглядит как С++. Кликнув мышкой вы увидите пару тегов в текущей позиции: [CPP][/CPP] Если там написать std::cout<<"Hello"; Получим: [CPP]std::cout<<"Hello";[/CPP] и в готовом отображаемом читателям тексте оно будет выглядеть как:
Что касается указателя на предикат, передаваемого условной переменной, то работу в нём делать вообще не желательно (мягко говоря). Это простая встраиваемая (как правило) функция которая возвращает bool. Это обычно лямбда даже. Вы можете целый день таскать контейнеры, укладывать их штабелями, сгребать и разгребать, а в момент когда результат достигнут (и украшен прекрасными цветами) вы устанавливаете переменную bool (можно и сайдэффектом обойтись, но я пока советую вручную) которую вернёт ваш предикат. А потом вызываете wait. Почитайте о том как это работает. Я уже кое где упомянул даже в этом топике.
1
|
97 / 0 / 1
Регистрация: 01.07.2018
Сообщений: 25
|
||||||
03.06.2020, 11:11 [ТС] | 39 | |||||
Спасибо за подсказку с тегами. Где именно в этой программе вызывать wait?
0
|
Комп_Оратор)
|
|
03.06.2020, 12:06 | 40 |
Рад что смог помочь.
Вот: Но он вызван не так как я вам предложил. Дайте методу wait мютекс unique_mutex - обёртка облегчающая управление. И дайте ему метод который он будет запускать по окончании сна в своём внутреннем (невидимом цикле ожидания) чтобы понять - просыпаться и хватать мутекс и делать вашу таску или спать дальше и ждать. Для этого посмотрите мой код. Или можете воспользоваться решением oleg-m1973, для моей задачи. Там легче принимать решение из корневого потока ( main() ).Главное, это то что код задачи не размещён в предикате. Он в защищаемой секции размещён. А мьютекс включает-выключает условная переменная. Это даёт возможность разгрузить партнёрский поток от нескончаемого вопроса: "ну ты закончил или нет?!". Переменная разлочит свою часть и уводит спать свой поток. Партнёр сам уведомляет о финише, - будит. А cv при пробуждении проверяет условие и возвращает управление своему потоку захватив мутекс. Теперь партнёр ждёт. Он может быть под простым мутексом, кстати. Я сделал симметрично, но это не обязательно. Добавлено через 7 минут Dgamilya, если вам только время нужно, то наверное то, что я показал, - лишнее.
0
|
03.06.2020, 12:06 | |
03.06.2020, 12:06 | |
Помогаю со студенческими работами здесь
40
Синхронизация потоков синхронизация потоков Синхронизация потоков в c++ Синхронизация потоков Синхронизация потоков Event c++ Синхронизация потоков на семафорах Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |