Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.58/12: Рейтинг темы: голосов - 12, средняя оценка - 4.58
 Аватар для Eraston
60 / 11 / 4
Регистрация: 09.09.2014
Сообщений: 182

std::condition_variable . для выделенных потоков

19.04.2021, 21:19. Показов 2447. Ответов 6
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте!
Попробовал модно реализовать переключение потоков в активный режим с std::condition_variable.
Вероятно возникла проблема с ситуацией, когда notify_one() вызывается до wait(), и случается дедлок. Как можно сие разрешить?
FTM: С затычкой на строке 57 вроде как бы работает, в лабораторных условиях.
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>
#include <thread>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <string>
#include <chrono>
 
const size_t COUNT = 5;
size_t ARRAY[COUNT];
std::condition_variable cvGen;
struct s_thread{
    std::atomic_bool nonstop;
    std::atomic_bool terminate;
    std::atomic_bool launch;
    std::mutex mtxOn;
    std::condition_variable cvOn;
    std::condition_variable cvDone;
    std::thread *t;
    size_t k;
};
 
void thread( s_thread *it ){
    while( it->nonstop ){
        std::unique_lock<std::mutex> lockOn( it->mtxOn );
        while( !it->launch || it->nonstop == false ) // Проверить условие продолжения работы
            it->cvOn.wait( lockOn ); // Ждать
        if( it->launch && it->nonstop == true ){
            // .....
            it->launch = false; // Флаг потока - окончил
            it->cvDone.notify_one(); // Уведомить об окончании
        }
        else{
            // std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
        }
    }
    // ~~ Костыль
    it->terminate = true;
}
 
#define i_to_COUNT size_t i=0;i<COUNT;i++
 
int main(){
    s_thread th[COUNT];
    // .....
            for( size_t j = 0; j < 100000; j++ ){
                // ~~ "Включить" потоки
                for( i_to_COUNT ){
                    //std::cout << "Launch " << i << "...\n";
                    th[i].launch = true;
                    th[i].cvOn.notify_one();
                }
                // ~~ Ожидание сигналов завершения от потоков
                for( i_to_COUNT ){
                    std::unique_lock<std::mutex> lockDone( th[i].mtxOn );
                    while( th[i].launch ){
                        th[i].cvOn.notify_one(); // !! Повторить потоку, что пора просыпаться
                        th[i].cvDone.wait( lockDone ); // Ждать
                        //std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
                    }
                }
            }
            for( i_to_COUNT ){
                std::cout << ARRAY[i] << " ";
            }
            std::cout << "\n";
    // .....
}
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
19.04.2021, 21:19
Ответы с готовыми решениями:

C++11, потоки, std::condition_variable
Проблема в том, что в коде ниже сначала работает лишь поток th1, а затем только th2 (поток th1 бездействует). Хотелось бы, чтобы при...

Сложение результата работы двух потоков. std::thread
Здравствуйте, есть два потока, std::thread thr(Sum,B,Z,std::ref(sum)),std::thread thr1(Sum, C, Z, std::ref(sum)), которые используют одну и...

Операция std::cout для Объекта типа std::string
Кто детально объяснит почему не выводит ? Дает вот так &quot;Отсутствует оператор &quot;&lt;&lt;&quot;, соответствующий этим операндам&quot; ...

6
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
19.04.2021, 22:14
Цитата Сообщение от Eraston Посмотреть сообщение
Как можно сие разрешить?
Для начала рассказать, что именно ты пытаешься сделать. А то по твоему коду довольно сложно понять.
0
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
19.04.2021, 22:48
Лучший ответ Сообщение было отмечено Eraston как решение

Решение

Цитата Сообщение от Eraston Посмотреть сообщение
проблема с ситуацией, когда notify_one() вызывается до wait(), и случается дедлок. Как можно сие разрешить?
Вот это:
Цитата Сообщение от Eraston Посмотреть сообщение
// ~~ "Включить" потоки
делать под блокировкой mutex'а.

Цитата Сообщение от Eraston Посмотреть сообщение
nonstop
Кто и как управляет этим флагом?
Кто и где проверяет костыль и зачем он вообще нужен если есть nonstop?

Атомики, да ещё и с sequentially-consistent упорядочиванием тут явно не нужны.
1
 Аватар для Eraston
60 / 11 / 4
Регистрация: 09.09.2014
Сообщений: 182
20.04.2021, 00:02  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
делать под блокировкой mutex'а.
Блокировка мьютекса над включением:
Упорядоченная (внезапно) активность потоков, более медленное выполнение.
0123401234012340123401234012340123401234 0123401234012340123401234012340123401234 01234012340123401234
100000 100000 100000 100000 100000 For 27.344s
Блокировка мьютекса после включения перед ожиданием:
Хаотичная (вроде) активность потоков, более быстрое выполнение.
0324110234012340213401234031240123402134 0123421034032411204320134012340123402134 02314021341203402143
100000 100000 100000 100000 100000 For 21.807s
Типа, пока не вник, как это работает, но в первом случае похоже, что потоки работают последовательно и ожидают выполнения друг друга...
0
 Аватар для Eraston
60 / 11 / 4
Регистрация: 09.09.2014
Сообщений: 182
20.04.2021, 00:04  [ТС]
Скрин
Миниатюры
std::condition_variable . для выделенных потоков   std::condition_variable . для выделенных потоков  
0
 Аватар для Eraston
60 / 11 / 4
Регистрация: 09.09.2014
Сообщений: 182
23.04.2021, 10:53  [ТС]
Цитата Сообщение от zayats80888 Посмотреть сообщение
делать под блокировкой mutex'а.
Цитата Сообщение от Eraston Посмотреть сообщение
Блокировка мьютекса над включением:
Цитата Сообщение от Eraston Посмотреть сообщение
похоже, что потоки работают последовательно и ожидают выполнения друг друга...
Что в принципе логично, основной поток лочит мьютекс [i] и анлочит только когда начинает ждать condition_variable [i], тогда поток [i] может залочить мьютекс [i], что он и должен сделать в своём wait()-e.

Добавлено через 23 минуты
Соответственно пришёл к такому решению с использованием совета
Цитата Сообщение от zayats80888 Посмотреть сообщение
делать под блокировкой mutex'а.
Код
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
39
40
41
42
43
// ...
 
std::condition_variable cvGen;
 
void thread( s_thread *it ){
    do{
        std::unique_lock<std::mutex> lockOn( it->mtxOn );
        cvGen.wait( lockOn, [&](){return it->launch == true || it->nonstop == false; } );
        if( it->launch ){
            // ~~ Калькулейтинг
            // ...
            it->launch = false; // Флаг потока - окончил
            it->cvDone.notify_one(); // Уведомить об окончании
        }
    } while( it->nonstop );
}
 
#define i_to_COUNT size_t i=0;i<COUNT;i++
 
int main(){
    // ...
    // ...
            for( size_t j = 0; j < 100000; j++ ){
                // ~~ "Включить" потоки
                for( i_to_COUNT ){
                    th[i].launch = true;
                }
                // ~~ Ожидание сигналов завершения от потоков
                for( i_to_COUNT ){
                    std::unique_lock<std::mutex> lockDone( th[i].mtxOn );
                    cvGen.notify_all();
                    th[i].cvDone.wait( lockDone, [&](){return th[i].launch == false; } );
                }
            }
            std::cout << "\n";
            for( i_to_COUNT ){
                std::cout << ARRAY[i] << " ";
            }
            std::cout << "For "<< float(clock() - cl)/CLOCKS_PER_SEC << "s \n";
    // ...
    // ...
    return 0;
}
Работать-то работает, вроде... Ну, и поток в глубокой теории может получать лишний notification, но флаг launch для него установлен не будет.
0
What a waste!
 Аватар для gray_fox
1610 / 1302 / 180
Регистрация: 21.04.2012
Сообщений: 2,733
24.04.2021, 01:28
Лучший ответ Сообщение было отмечено Eraston как решение

Решение

Eraston, тут "классическая" проблема потери нотификации о событии при использовании условной переменной

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

Чтобы избежать подобных ситуаций стоит, КМК (и как уже написал zayats80888) взять за правило всегда делать нотификацию при захваченом мюьтексе
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.04.2021, 01:28
Помогаю со студенческими работами здесь

std::getline Альтернатива для (std::string, int, char)
Есть у кого идеи? Есть строка чисел(разделены пробелами), хочу считывать числа до пробела в инт затем уже работать засунуть этот инт в...

std::begin, std::end для динамического массива c++
Работает нормально: int m = {1,2,3,4,5}; set &lt;int&gt; m_set{ begin(m),end(m) }; Не работает: int n;cin&gt;&gt;n; int *m =...

Не воспринимает ни std::cout, ни std::cin. Вобщем ничего из std. Также не понимает iostream
Здравствуйте! Я хотел начать изучать язык C++. Набрал литературы. Установил Microsoft Visual C++ 2005 Express Edition. Образ диска...

О потоках std::thread: можно ли вложить потоки друг в друга и можно ли создать динамический массив потоков?
1) Могу ли я вложить потоки друг в друга? 2) Могу ли я создать динамический массив потоков, каким-либо образом инициализировав их потом в...

ошибка error: cannot convert 'std::string {aka std::basic_string<char>}' to 'std::string* {aka std::basic_stri
на вод поступают 2 строки типа string. определить количество вхождений строки 2 в строку 1 ошибка error: cannot convert 'std::string {aka...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
SDL3 для Android: Загрузка PNG с альфа-каналом с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru