У меня есть 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 Я специально отключил синхронизацию, чтобы следить за их поведением! И задаю вопрос ПОЧЕМУ при одинаковой задержке одних и тех же потоков я получаю другой результат, чем без этой задержки.
ПОЧЕМУ, потому что у вас неопределенное поведение. Они могут делать «все». Внесение «изменений», которые ничего не меняют, может иметь значение, поскольку поведение не определено.
@NathanOliver Это ерунда, если бы это было так, я бы не задавал здесь этот вопрос. У меня результаты постоянные, а именно: с задержкой результат всегда 1, глобальная переменная в итоге равна 112. А без задержки результат другой и всегда равен 124!!
Как вы думаете, сколько раз эта демонстрация работал идеально, прежде чем Билл Гейтс вышел на сцену? Undefined Поведение не определено. Может быть, вы получите стабильные результаты. Может быть, вы не будете. Возможно, вы получите то, что ожидаете увидеть. Может быть, вы не будете. Исправьте неопределенное поведение и повторите тестирование.
В зависимости от планирования потоков вашей операционной системы при добавлении задержки все два потока выполняются i = global
, глобальное значение одинаково для двух потоков. Так что это просто увеличение на 12. Когда задержки нет, код:
i = global;
i++;
global = i;
не был прерван, что эквивалентно global++
здесь. Таким образом, результат 100 + 12 * 2 = 124.
этот код еще можно прервать. даже global++
можно прервать. без использования сблокированного приращения или критической секции результат может быть любым от 112 до 124
Да, это зависит от поведения системы. Я имею в виду «базировать на операционной системе OP».
Прежде чем поток выполнит i = global;
, другой поток увеличил его. Это явление в его системе.
Ваш код имеет неопределенное поведение. Вы не можете совместно использовать переменную между потоками без синхронизации.