Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
16 / 18 / 2
Регистрация: 02.03.2024
Сообщений: 510

Изменение переменной и отработка её значения в другом потоке, казалось бы элементарная задача

23.09.2024, 23:35. Показов 1177. Ответов 10
Метки нет (Все метки)

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

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


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

Вопрос почему?


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
#include <iostream>
#include <fstream> // для файла записи
#include "time.h" // для времени
#include <windows.h>
#include <thread> // для потоков
 
bool doCPU = true;
 
int main()
{
 
std::thread t1([&]()
        {
            cout << "Thread " << *std::this_thread::get_id << " was started\n";
            int g = 0;
            while (doCPU) {
                g++;
            }
            cout << "CPU was stoped\n";
        });
 
 
// ждем пока новый поток запустится
        std::this_thread::sleep_for(std::chrono::seconds(5));
 
        doCPU = false;
        if(t1.joinable())
            t1.join();
 
}
Добавлено через 4 минуты
получилось вот так
, что странно

C++
1
2
3
4
5
6
7
8
9
10
11
12
в одном потоке 
while (true) {
                mtx.lock();
                if (!doCPU)
                    break;
                mtx.unlock();
                g++;
            }
в основном теле 
mtx.lock();
        doCPU = false;
        mtx.unlock();
вопрос
как условие whileобрамить в мутекс?

Добавлено через 2 минуты
вообще почему здесь нужен мутекс?
у нас же нет изменения переменной в обоих потоках
более того применение мутекса оно заставляет другой поток ждать.
а это противоречит концепции.
т.е. получается надо изменять промежуточную переменную в основном теле - принимать на ввод от пользователя,
и потом введенное значение присваивать целевой переменной.
какая-то муть получилась.
а есть способы проще?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
23.09.2024, 23:35
Ответы с готовыми решениями:

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

Как получить значение переменной созданной в потоке, в другом потоке?
Добрый день :) Возник такой вопрос &quot;как получить значение переменной созданной в потоке, в другом потоке?&quot; Не знаю, как правильно...

Управление потоками. Изменение значения label (созданного в потоке 1) в потоке 2
Код таков: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; ...

10
434 / 156 / 28
Регистрация: 12.12.2020
Сообщений: 1,255
23.09.2024, 23:38
Переменную объявите как volatile. Компилятор видит что она в потоке не меняется и оптимизирует код, вообще выкидывая проверку.
2
16 / 18 / 2
Регистрация: 02.03.2024
Сообщений: 510
23.09.2024, 23:55  [ТС]
Цитата Сообщение от Alex1126 Посмотреть сообщение
Компилятор видит что она в потоке не меняется и оптимизирует код, вообще выкидывая проверку.
а почему тогда с мутексом сработало?

Добавлено через 1 минуту
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
std::thread t1([&]()
        {
            cout << "Thread " << *std::this_thread::get_id << " was started\n";
            int g = 0;
            while (true) {
                mtx.lock();
                if (!doCPU)
                    break;
                mtx.unlock();
                g++;
            }
            cout << "CPU was stoped\n";
        });
 
        std::this_thread::sleep_for(std::chrono::seconds(5));
        mtx.lock();
        doCPU = false;
        mtx.unlock();
        
        if(t1.joinable())
            t1.join();
Добавлено через 2 минуты
Цитата Сообщение от Alex1126 Посмотреть сообщение
Переменную объявите как volatile. Компилятор видит что она в потоке не меняется и оптимизирует код, вообще выкидывая проверку.
действительно
работает volatile
как -то можно запретить компилятору такие куда его не просят оптимизации?
0
434 / 156 / 28
Регистрация: 12.12.2020
Сообщений: 1,255
24.09.2024, 01:35
Мутекс он так же говорит компилятору что эта переменная где то меняется. Но в данном случае помоему более правильно использовать волатиле, так как мутекс отвечает за синхронизацию доступа разных потоков к одному ресурсу. У вас же ничего такого не требуется.

Можно попробовать запускать компилятор без оптимизиции, но незнаю, насколько это поможет. Волатиле - это то что тут надо использовать. И привыкать надо именно к такому, а не отключать у компилятора оптимизацию Это даст однозначное поведение кода при всех "режимах".
1
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13177 / 6813 / 1821
Регистрация: 18.10.2014
Сообщений: 17,238
24.09.2024, 01:56
Лучший ответ Сообщение было отмечено pup_kin как решение

Решение

Цитата Сообщение от pup_kin Посмотреть сообщение
а почему тогда с мутексом сработало?
Потому что, во-первых, вызов любой функции, определенной в другой единице трансляции, приведет к тому, что код начнет "работать". Ваша переменная доступна глобально. Компилятор ничего не знает о функции из другой единицы трансляции. Он не может знать, меняет ли эта функция эту глобальную переменную или нет. Даже добавление обычного вызова printf может заставить ваш код "работать" (хотя printf - не самый лучший пример).

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

Цитата Сообщение от pup_kin Посмотреть сообщение
как -то можно запретить компилятору такие куда его не просят оптимизации?
Никак. Ваша программа изначально неработоспособна по правилам языка С++. Оптимизации тут ни при чем.
1
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
24.09.2024, 06:31
Цитата Сообщение от Alex1126 Посмотреть сообщение
Переменную объявите как volatile
это неправильно. volatile говорит лишь о том, что объект будет меняться не из нашего процесса, никакой синхронизации ему таким образом не добавляется. Нужно использовать мутекс или атомик


лечение в данном случае:
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
#include <iostream>
#include <thread>
#include <atomic>
 
std::atomic<bool> doCPU = true;
 
int main()
{
    using namespace std::chrono_literals;
    
    std::thread t1([]
    {
        std::cout << "Thread " << *std::this_thread::get_id << " was started\n";
        int g = 0;
        while (doCPU)
        {
            g++;
        }
        std::cout << "CPU was stoped\n";
    });
 
    //ждем 5 секунд, пока поток переполнит тип int, лол
    std::this_thread::sleep_for(5s);
    
    doCPU = false;
    t1.join();
}
1
1476 / 490 / 73
Регистрация: 22.09.2023
Сообщений: 1,507
24.09.2024, 09:17
Цитата Сообщение от Алексей1153 Посмотреть сообщение
это неправильно. volatile говорит лишь о том, что объект будет меняться не из нашего процесса
Что и требуется в данном конкретном случае.
Цитата Сообщение от Алексей1153 Посмотреть сообщение
икакой синхронизации ему таким образом не добавляется.
В данном конкретном случае она и не требуется.
1
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
24.09.2024, 09:24
Dushevny, другой процесс эту переменную менять не может, не вижу, чтобы такое было в коде возможно

а вот гонка данных есть

чтение в одном потоке
Цитата Сообщение от pup_kin Посмотреть сообщение
while (doCPU) {
запись в другом потоке
Цитата Сообщение от pup_kin Посмотреть сообщение
doCPU = false;
1
1476 / 490 / 73
Регистрация: 22.09.2023
Сообщений: 1,507
24.09.2024, 09:42
Цитата Сообщение от Алексей1153 Посмотреть сообщение
запись в другом потоке
Да, но запись только одна. Если бы было несколько записей и каждая писала свое значение - да, синхронизация была бы нужна. Но тут в двух местах в doCPU пишется одно и то же значение false, то есть значение false будет записано в переменную даже в том случае, если эти две записи наложатся во времени.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
а вот гонка данных есть
Не вижу тут гонки. Событие doCPU = false; может произойти до или после чтения по внешним причинам и введение синхронизации кроме замедления цикла ничего к поведению программы не добавит. "Я так думаю!"
1
фрилансер
 Аватар для Алексей1153
6465 / 5678 / 1131
Регистрация: 11.10.2019
Сообщений: 15,118
24.09.2024, 09:57
Цитата Сообщение от Dushevny Посмотреть сообщение
Не вижу тут гонки.
а я вижу
1
16 / 18 / 2
Регистрация: 02.03.2024
Сообщений: 510
24.09.2024, 16:03  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Даже добавление обычного вызова printf может заставить ваш код "работать" (хотя printf - не самый лучший пример).
да совершенно верно
добавление
cout
также заставляло работать.
я подумал, что это какие очереди к потокам ввода вывода

Добавлено через 4 минуты
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ваша программа изначально неработоспособна по правилам языка С++.
не понял.
что имеется ввиду - неправильные объекты или организация работы с потоками?
почему не работоспособна?
это не программа это кусок вырванный из контекста,
так то конечно в основном потоке идет ожидание ввода пользователя.
и кстати очень интересно
если например я ввожу переменную которую через мутексы отрабатываю в потоках, то одидание ввода не нужно делать на этой переменной, нужен буфер
типа

C++
1
2
3
4
5
6
7
8
char ch;
while(cin>>ch)
{
mtx.lock();
переменнаяОбрабатываемаяВпотоках = ch;
mtx.unlock();
 
}
а есть какой-то способ другой?

Добавлено через 3 минуты
Цитата Сообщение от Алексей1153 Посмотреть сообщение
а я вижу
ну вообще по идее
изначально гонка была
потому что один поток - несерьезно.
но потом выяснилось что не работает, и был написан один поток.
там вообще массив потоков.
и наверное одну переменную объявлятть для работы во всех потоках - не есть гуд.
наверное надо объявить для каждого потока свою переменную, например маммис потоков и массив переменных для каждого потока,
и меняться они будут из основного цикла , копированием например.

Но меня интересует
почему программа не работоспособна в парадигме с++
очень интересно.

Добавлено через 1 минуту
в данном случае гонки нет
потому что чтения булева типа - можно сказать атомарно.- порчи данных не будет,
[даже если в момент начала чтения
переменная булева была 00000001,
и в процессе изменилась на 00000000 - то она также консистентна, тут же один конденсатор]
если будет другой тип - то наверное будет гонка
это надо проверить.

Добавлено через 1 час 39 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ваша программа изначально неработоспособна по правилам языка С++. Оптимизации тут ни при чем.
очень интересно - что Вы имели ввиду.
p.s.
как выяснилось с++ очень современный язык, поддерживающий все модные лексеммы имеющиеся в других языках.

Добавлено через 50 минут
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Потому что, во-первых, вызов любой функции, определенной в другой единице трансляции, приведет к тому, что код начнет "работать". Ваша переменная доступна глобально. Компилятор ничего не знает о функции из другой единицы трансляции. Он не может знать, меняет ли эта функция эту глобальную переменную или нет. Даже добавление обычного вызова printf может заставить ваш код "работать" (хотя printf - не самый лучший пример).
это полезно, не знал.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
24.09.2024, 16:03
Помогаю со студенческими работами здесь

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

Dispatcher.Invoke, присвоение переменной созданной в другом потоке свойству UI элемента
Добрый день. Есть код на wpf model3D = Init3DModel(); ... var backMat = new DiffuseMaterial(new ImageBrush(wb)); ...

Вывести значения коллекции в другом потоке
не дается мне многопоточность, если кто может помочь, помогите. using System; using System.Collections.Generic; using System.Linq;...

Изменение Javascript переменной в другом фрейме! Помогите плз!
Есть 2 фрейма top и menu. В меню по клику надо изменить variable из фрейма top. Т.е. в фрейме top есть переменная x которя равна 1,...

Работа с Dictionary в одном потоке, при этом он может изменятся в другом потоке
Здравствуйте! Я делаю лабу сервер распределенных вычислений в сети. В одном потоке ожидаю клиентов и на каждого клиента создаю поток. ...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
Хочу заставить корпорации вкладываться в здоровье сотрудников: делаю мат модель здравосохранения
anaschu 22.03.2026
e7EYtONaj8Y Z4Tv2zpXVVo https:/ / github. com/ shumilovas/ med2. git
1С: Программный отбор элементов справочника по группе
Maks 22.03.2026
Установка программного отбора элементов справочника "Номенклатура" из модуля формы документа. В качестве фильтра для отбора справочника служит группа номенклатуры. Отбор по наименованию группы. . .
Как я обхитрил таблицу Word
Alexander-7 21.03.2026
Когда мигает курсор у внешнего края таблицы, и нам надо перейти на новую строку, а при нажатии Enter создается новый ряд таблицы с ячейками, то мы вместо нервных нажатий Энтеров мы пишем любые буквы. . .
Krabik - рыболовный бот для WoW 3.3.5a
AmbA 21.03.2026
без регистрации и смс. Это не торговля, приложение не содержит рекламы. Выполняет свою непосредственную задачу - автоматизацию рыбалки в WoW - и ничего более. Однако если админы будут против -. . .
1С: Программный отбор элементов справочника по значению перечисления
Maks 21.03.2026
Установка программного отбора элементов справочника "Сотрудники" из модуля формы документа. В качестве фильтра для отбора служит значение перечислений. / / Событие "НачалоВыбора" реквизита на форме. . .
Переходник USB-CAN-GPIO
Eddy_Em 20.03.2026
Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и был разработан. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто. . .
Оттенки серого
Argus19 18.03.2026
Оттенки серого Нашёл в интернете 3 прекрасных модуля: Модуль класса открытия диалога открытия/ сохранения файла на Win32 API; Модуль класса быстрого перекодирования цветного изображения в оттенки. . .
SDL3 для Desktop (MinGW): Рисуем цветные прямоугольники с помощью рисовальщика SDL3 на Си и C++
8Observer8 17.03.2026
Содержание блога Финальные проекты на Си и на C++: finish-rectangles-sdl3-c. zip finish-rectangles-sdl3-cpp. zip
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru