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

#c #windows #winapi #critical-section

#c #Windows #winapi #критический раздел

Вопрос:

У меня есть 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 M 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 M M n", " 2 th", i, j );     
    } 
    return 0; 
} 
int _tmain(int argc, _TCHAR* argv[]) { 
    HANDLE msh[2]; 
    ht1 = CreateThread(NULL, 0, amp;ThreadProc1, NULL, 0, NULL); 
    ht2 = CreateThread(NULL, 0, amp;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

Комментарии:

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

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

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

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

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

Ответ №1:

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

 i = global;      
i  ;     
global = i;
  

не было прервано, эквивалентно global here . Итак, результат 100 12*2 = 124.

Комментарии:

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

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

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