Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/15: Рейтинг темы: голосов - 15, средняя оценка - 5.00
97 / 0 / 1
Регистрация: 01.07.2018
Сообщений: 25
1

Синхронизация потоков с time_point

28.05.2020, 12:08. Показов 2966. Ответов 41
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
В программе запускается два потока, первым-поток, ожидающий инструкций от пользователя( выводит строку, ожидает ввод, запускает соответствующую функцию-либо изменяет общий контейнер, либо выводит из него данные), вторым запускается поток, выводящий точно по time_point данные из общего контейнера. Как синхронизировать потоки? Приложение пока консольное, проблема в том, что второй поток должен всегда точно по времени выводить сообщения и если первый считает информацию слишком поздно( не успеет выполнить вывод до очередной временной точки), то вывод со второго потока не успеет сработать вовремя. Думаю использовать timed_mutex, блокировать второй поток точно по времени, а в первом использовать try_lock_until( time_point-chrono::milliseconds(500). Есть ли более оптимальный вариант?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
28.05.2020, 12:08
Ответы с готовыми решениями:

Как привести тип time_point<std::filesystem::__file_clock, [.]>к типу const time_point<std::chrono::_V2::system_clock
Если использовать std::experimental::filesystem::v1 то можна сделать вот так : ...

Синхронизация потоков
Есть статический класс к которому я хочу обращаться из разных потоков static class MyLog {...

Синхронизация потоков
Снова привет. Есть у меня код, который требуется раскидать на потоки. Ниже код: #include...

Синхронизация потоков - C++
Что это? Как это исправить? &quot;ConsoleApplication2.exe&quot; (Win32). Загружено...

41
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 18:47 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну, во-первых - не надо здесь вызывать cv.wait с функцией - у тебя уже есть цикл ожидания, зачем в нём второй, вложенный?
Это интересный вопрос. На мой взгляд тут всё дело в автоматическом захвате-освобождении мьютекса, а как ОС реализует слип это её вопрос. Важно что не спинлочит. А внешний цикл - да это цикл контроллера. Я же не однократное действо проворачиваю в задачах. Там конвейер (примитивны конечно).
Вообще интересный разговор. Буду думать.

Добавлено через 2 минуты
Цитата Сообщение от zayats80888 Посмотреть сообщение
Где гарантия, что эти операции синхронизированы?
переменная, сон, конвейер. Запустите и посмотрите, что происходит. Последовательность действий задана строго. Другой вопрос, что не ясно когда весь рабочий процесс свернётся. Это зависит от копыта ударившего по клаве. Но так же и задумано. Иначе всё сложнее пришлось бы делать.
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
02.06.2020, 18:49 22
Цитата Сообщение от IGPIGP Посмотреть сообщение
Это интересный вопрос. На мой взгляд тут всё дело в автоматическом захвате-освобождении мьютекса, а как ОС реализует слип это её вопрос
wait с предикатом это всего лишь, не более того
C++
1
2
3
4
2) Equivalent to
while (!pred()) {
    wait(lock);
}
https://en.cppreference.com/w/... iable/wait
Блокировка здесь ни при чём
0
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
02.06.2020, 18:51 23
Цитата Сообщение от IGPIGP Посмотреть сообщение
переменная, сон, конвейер
Вы про планировщик задач ОС забыли.
Цитата Сообщение от IGPIGP Посмотреть сообщение
Иначе всё сложнее пришлось бы делать.
Достаточно сделать её (continue_work) атомарной.
1
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 18:52 24
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну, здесь можно и с предикатом, только в нём, кроме printed и filled, правильно проверять ещё и continue_work
Наверно и так можно. Это хорошая идея и я подумаю. Важно, чтобы после окончания потока печати добавитель не затолкал в вектор что-то что уже не напечатается. То есть, надо сделать так, чтобы они вывалились в правильной последовательности. Печатающий должен быть последним)
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
02.06.2020, 18:53 25
Цитата Сообщение от zayats80888 Посмотреть сообщение
Достаточно сделать её (continue_work) атомарной.
Зачем? volаtile вполне достаточно
0
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
02.06.2020, 18:55 26
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
volаtile вполне достаточно
Может в MSVS и достаточно, но стандарт не определяет store/load операции над volitilte переменными как атомарные.
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
02.06.2020, 18:57 27
Цитата Сообщение от zayats80888 Посмотреть сообщение
Может в MSVS и достаточно, но стандарт не определяет store/load операции над volitilte переменными как атомарные.
Ну и что? Что здесь поменяется от того, что эта операция не будет атомарной, continue_work никогда не станет false?
1
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 18:58 28
Цитата Сообщение от zayats80888 Посмотреть сообщение
Достаточно сделать её (continue_work) атомарной.
Опять вы не поняли.
Цитата Сообщение от zayats80888 Посмотреть сообщение
Вы про планировщик задач ОС забыли.
Да пусть планировщик заснёт на пол секунды. Ну и что? Оба брата-акробата напихают больше огурцов. Но первый (единственный - точнее) получит новое значение continue_work именно печатающий. Он перекроет кислород заталкивающему перед нотификацией. Он подмутексом пишет переменную
C++
1
continue_push=false;
выключая цикл пушера. А пушер про:
C++
1
continue_work
вообще не знает.
0
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
02.06.2020, 19:08 29
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну и что? Что здесь поменяется от того, что эта операция не будет атомарной, continue_work никогда не станет false?
Как я уже сказал
Мне трудно представить, как можно нарушить инвариант в конкретно вашем случае(bool либо true, либо false)
Но это не значит, что код корректен.

Добавлено через 6 минут
Цитата Сообщение от IGPIGP Посмотреть сообщение
Опять вы не поняли
Да нет, я понимаю как работает ваш код.
Цитата Сообщение от IGPIGP Посмотреть сообщение
continue_push=false;
Я говорю про две конкретные операции, запись и чтение continue_work, при чём тут continue_push?
0
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 19:14 30
Цитата Сообщение от zayats80888 Посмотреть сообщение
Но это не значит, что код корректен.
zayats80888, похоже вы не хотите представить о чём речь идёт.
Ответьте на простой вопрос: изменение значения continue_work когда-нибудь отловится в потоке задачи печати (больше ни кто эту переменную не контролирует) ?

Добавлено через 1 минуту
Цитата Сообщение от zayats80888 Посмотреть сообщение
Я говорю про две конкретные операции, запись и чтение continue_work, при чём тут continue_push?
Покажите их в коде и скажите какое это может иметь значение.

Добавлено через 2 минуты
Цитата Сообщение от zayats80888 Посмотреть сообщение
при чём тут continue_push?
Тогда кто и с кем тут может погоняться?
0
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
02.06.2020, 19:18 31
Цитата Сообщение от IGPIGP Посмотреть сообщение
изменение значения continue_work когда-нибудь отловится в потоке задачи печати (больше ни кто эту переменную не контролирует) ?
Я уже дважды повторил, что с bool переменной, мне трудно представить нарушение инварианта.
Но у вас запись и чтение не атомарной переменной не синхронизированны!
Я поясню так:
C++
1
2
3
4
5
6
7
8
9
10
11
volatile int  val = INIT_VALUE;
void thread1()
{
    while (val != SOME_VALUE_1);
    this_should_not_be_done(); // нет гарантий, что это никогда не выполнится.
}
 
void thread2()
{
   val = SOME_VALUE_2;
}
0
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 19:27 32
Цитата Сообщение от zayats80888 Посмотреть сообщение
Но у вас запись и чтение не атомарной переменной не синхронизированны!
Я поясню так:
У меня булева перемнная. Это даже не char. Что касается гарантий, то глобальные переменные у потоков одного процесса общие. Поэтому, мне кажется, что вы повторяете некую формальную мантру.
Думаю, не стоит это продолжать, я почитаю ещё, конечно и найдя приличные примеры у того же Уильямса - покажу. Продолжение ни чего не даст, так как доказательств нет ни у одной из сторон.
0
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
02.06.2020, 19:34 33
Цитата Сообщение от IGPIGP Посмотреть сообщение
так как доказательств нет ни у одной из сторон
When an evaluation of an expression writes to a memory location and another evaluation reads or modifies the same memory location, the expressions are said to conflict. A program that has two conflicting evaluations has a data race unless
both evaluations execute on the same thread or in the same signal handler, or
both conflicting evaluations are atomic operations (see std::atomic), or
one of the conflicting evaluations happens-before another (see std::memory_order)
If a data race occurs, the behavior of the program is undefined.
Это отсюда. Ссылки на стандарт я давать не умею.

Добавлено через 1 минуту
Цитата Сообщение от IGPIGP Посмотреть сообщение
Продолжение ни чего не даст
Ну не даст, так не даст. Я не настаиваю
0
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 20:09 34
Цитата Сообщение от zayats80888 Посмотреть сообщение
C++
1
2
or
one of the conflicting evaluations happens-before another (see std::memory_order)
Это же наш случай. Я это повторял много раз и ещё раз повторю. Вычисление с записью (если так удобно, пусть так) делается в main. Чтение производится циклически, и решение о остановке принимается после записи в main и ни как иначе. Порядок строго определён.

Добавлено через 46 секунд
Цитата Сообщение от IGPIGP Посмотреть сообщение
Последовательность действий задана строго.
вот тута я говорил

Добавлено через 14 минут
там можно было бы задать данную переменную с клавиатуры, а не присваивать после ввода любого символа. Но с учётом замечания oleg-m1973, про volalile это не нужно)
0
6105 / 3460 / 1406
Регистрация: 07.02.2019
Сообщений: 8,794
02.06.2020, 20:18 35
Цитата Сообщение от IGPIGP Посмотреть сообщение
Это же наш случай
Нет, посмотрите что такое memory_order

Добавлено через 7 минут
Цитата Сообщение от IGPIGP Посмотреть сообщение
у мкня Энтони Уильямс ещё не улёгся нормально.
Перечитайте 5 главу.
0
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
02.06.2020, 20:31 36
Цитата Сообщение от zayats80888 Посмотреть сообщение
Нет, посмотрите что такое memory_order
Я почитаю, конечно, но не понимаю как это может повлиять на последовательность операций в конкретно моём случае. Там разобраны разные вещи. в частности данные занимающие более одного байта и пр. Но почитаю. Пока что я не увидел тут сходных вещей кроме доказательства своей правоты. Порядок чтения и записи в моём случае железо-бетонный. Если я не прав, то тут слабое место, но я не могу себе это представить.
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
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
03.06.2020, 10:26 38
Цитата Сообщение от Dgamilya Посмотреть сообщение
Я не могу использовать CV.wait() потому, что в функции, через которую юзер общается с программой, порядка 10 различных вопросов, которые программа ему задает. С CV.wait() проходит только 1 вопрос на 1 вывод таймпоинта первым потоком.
Dgamilya, вы и тегами для кода не умеете пользоваться. Мы научим. Сначала попросим модераторов добавить вам теги.
А теперь смотрите на верхнюю линейку окна редактора, где набираете текст. Вторая позиция в среднем (2-м с верху/низу) ряду выглядит как С++. Кликнув мышкой вы увидите пару тегов в текущей позиции:
[CPP][/CPP]
Если там написать std::cout<<"Hello";
Получим:
[CPP]std::cout<<"Hello";[/CPP]
и в готовом отображаемом читателям тексте оно будет выглядеть как:
C++
1
std::cout<<"Hello";
Того же эффекта можно добиться выделив любой текст и кликнув пиктограммку тегов С++ (см. выше).
Что касается указателя на предикат, передаваемого условной переменной, то работу в нём делать вообще не желательно (мягко говоря). Это простая встраиваемая (как правило) функция которая возвращает bool. Это обычно лямбда даже. Вы можете целый день таскать контейнеры, укладывать их штабелями, сгребать и разгребать, а в момент когда результат достигнут (и украшен прекрасными цветами) вы устанавливаете переменную bool (можно и сайдэффектом обойтись, но я пока советую вручную) которую вернёт ваш предикат. А потом вызываете wait. Почитайте о том как это работает. Я уже кое где упомянул даже в этом топике.
1
97 / 0 / 1
Регистрация: 01.07.2018
Сообщений: 25
03.06.2020, 11:11  [ТС] 39
Спасибо за подсказку с тегами. Где именно в этой программе вызывать wait?

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
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_Ne xt );
unique_lock<mutex>UL1(MU);
CV.wait();
}
 
{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_Ne xt );
unique_lock<mutex>UL1(MU);
CV.wait();
}
 
{unique_lock<mutex>UL1(MU);
cout << "Enter the name";
}
 
cin >> Object;
0
Комп_Оратор)
Эксперт по математике/физике
8950 / 4704 / 629
Регистрация: 04.12.2011
Сообщений: 13,999
Записей в блоге: 16
03.06.2020, 12:06 40
Цитата Сообщение от Dgamilya Посмотреть сообщение
Спасибо за подсказку с тегами.
Рад что смог помочь.
Цитата Сообщение от Dgamilya Посмотреть сообщение
Где именно в этой программе вызывать wait?
Вот:
Цитата Сообщение от Dgamilya Посмотреть сообщение
C++
1
2
unique_lock<mutex>UL1(MU);
CV.wait();
Но он вызван не так как я вам предложил. Дайте методу wait мютекс unique_mutex - обёртка облегчающая управление. И дайте ему метод который он будет запускать по окончании сна в своём внутреннем (невидимом цикле ожидания) чтобы понять - просыпаться и хватать мутекс и делать вашу таску или спать дальше и ждать.
Для этого посмотрите мой код. Или можете воспользоваться решением oleg-m1973, для моей задачи. Там легче принимать решение из корневого потока (main()).
Главное, это то что код задачи не размещён в предикате. Он в защищаемой секции размещён. А мьютекс включает-выключает условная переменная. Это даёт возможность разгрузить партнёрский поток от нескончаемого вопроса: "ну ты закончил или нет?!". Переменная разлочит свою часть и уводит спать свой поток. Партнёр сам уведомляет о финише, - будит. А cv при пробуждении проверяет условие и возвращает управление своему потоку захватив мутекс. Теперь партнёр ждёт. Он может быть под простым мутексом, кстати. Я сделал симметрично, но это не обязательно.

Добавлено через 7 минут
Dgamilya, если вам только время нужно, то наверное то, что я показал, - лишнее.
0
03.06.2020, 12:06
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.06.2020, 12:06
Помогаю со студенческими работами здесь

Синхронизация потоков
Добрый день. Как синхронизировать потоки, чтобы вывод в stdout был поочередным: foo bar foo bar?...

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

Синхронизация потоков в c++
Совершенно не понятно что не так и как правильно. Задача: Отсортировать массив целых чисел....

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

Синхронизация потоков Event c++
Необходимо, чтобы нить t4 ждала события просчета времени &quot;time = 1000 * (getTime() - time);&quot; и...

Синхронизация потоков на семафорах
почему не работает синхронизация потоков на семафорах? при компиляции ошибка сегментирования. На...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru