Почему одинаковая задержка в одних и тех же потоках влияет на результат?

У меня есть 2 несинхронизированных потока, которые изменяют глобальную переменную. Каждый поток имеет 12 итераций. Перед командой модификации каждый поток имеет задержку в 1 мс. В итоге глобальная переменная равна 112, что логично, так как потоки модифицируют ее одновременно, НО если убрать задержку в обоих потоках, то один из них опережает другой поток, так что другой поток получает текущее значение глобальной переменной. Почему это происходит, когда задержки включены?

#include "stdafx.h" 
#include <windows.h> 
#include <iostream> 
#include <omp.h>
using namespace std;

int global = 100;
HANDLE ht1, ht2; 
DWORD WINAPI ThreadProc1(LPVOID lpParameter ) { 
    int i, j;   
    for (j=1; j <= 12; j++)    {
        i = global;      
        i++;     
        Sleep (1);  //Delay before modifying global variable
        global = i; 
        printf_s( "%4s %4d \n", " 1 th", i );    
    } 
    return 0;  
}
DWORD WINAPI ThreadProc2 (LPVOID lpParameter) { 
    int i, j; 
    for (j=1; j <= 12; j++)    {   
        i = global;      
        i++;     
        Sleep (1);  //Delay before modifying global variable     
        global = i;
        printf_s( "%4s %4d %4d \n", " 2 th", i, j );     
    } 
    return 0; 
} 
int _tmain(int argc, _TCHAR* argv[]) { 
    HANDLE msh[2]; 
    ht1 = CreateThread(NULL, 0, &ThreadProc1, NULL, 0, NULL); 
    ht2 = CreateThread(NULL, 0, &ThreadProc2, NULL, 0, NULL); 
    msh[0] = ht1; 
    msh[1] = ht2;
    WaitForMultipleObjects(2,msh,TRUE, INFINITE);
    return 0; 
} 

отсроченный результат https://i.imgur.com/EMOQfTj.png

результат без задержек https://i.imgur.com/Ilgz824.png

Ваш код имеет неопределенное поведение. Вы не можете совместно использовать переменную между потоками без синхронизации.

NathanOliver 09.04.2019 18:43

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

Jesper Juhl 09.04.2019 18:45

дополнение к моему комментарию: вы не можете поделиться переменной, в которую пишете. Если все ваши потоки только читают (ни один поток не будет выполнять запись), вам не нужна синхронизация.

NathanOliver 09.04.2019 18:49

Пожалуйста, не делайте размещайте изображения данных (особенно не в виде внешних ссылок). Укажите дату как текст, в вопрос.

Jesper Juhl 09.04.2019 18:53

@NathanOliver Я специально отключил синхронизацию, чтобы следить за их поведением! И задаю вопрос ПОЧЕМУ при одинаковой задержке одних и тех же потоков я получаю другой результат, чем без этой задержки.

volvo 09.04.2019 19:11

ПОЧЕМУ, потому что у вас неопределенное поведение. Они могут делать «все». Внесение «изменений», которые ничего не меняют, может иметь значение, поскольку поведение не определено.

NathanOliver 09.04.2019 19:23

@NathanOliver Это ерунда, если бы это было так, я бы не задавал здесь этот вопрос. У меня результаты постоянные, а именно: с задержкой результат всегда 1, глобальная переменная в итоге равна 112. А без задержки результат другой и всегда равен 124!!

volvo 09.04.2019 19:31

Как вы думаете, сколько раз эта демонстрация работал идеально, прежде чем Билл Гейтс вышел на сцену? Undefined Поведение не определено. Может быть, вы получите стабильные результаты. Может быть, вы не будете. Возможно, вы получите то, что ожидаете увидеть. Может быть, вы не будете. Исправьте неопределенное поведение и повторите тестирование.

user4581301 09.04.2019 20:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В зависимости от планирования потоков вашей операционной системы при добавлении задержки все два потока выполняются i = global, глобальное значение одинаково для двух потоков. Так что это просто увеличение на 12. Когда задержки нет, код:

i = global;      
i++;     
global = i;

не был прерван, что эквивалентно global++ здесь. Таким образом, результат 100 + 12 * 2 = 124.

этот код еще можно прервать. даже global++ можно прервать. без использования сблокированного приращения или критической секции результат может быть любым от 112 до 124

RbMm 10.04.2019 10:48

Да, это зависит от поведения системы. Я имею в виду «базировать на операционной системе OP».

Drake Wu 10.04.2019 10:59

Прежде чем поток выполнит i = global;, другой поток увеличил его. Это явление в его системе.

Drake Wu 10.04.2019 11:07

Другие вопросы по теме