Визуальное программирование и MFC



Использование критических секций


Для начала рассмотрим следующий пример. Простейшим средством коммуникации между потоками процесса являются глобальные переменные, так как всем потокам процесса доступны все глобальные переменные процесса. Допустим, рабочий поток в процессе вычисления увеличивает и проверяет значение глобальной целочисленной переменной, завершаясь, когда значение переменной достигает 100. Основной поток может принудительно завершить рабочий поток, присвоив глобальной переменной значение 100 или более. Приведенный ниже код функции потока на первый взгляд должен работать именно так, как ожидается:

int g_count; // глобальная переменная …… UINT MyThread(LPVOID pParam) { g_count=0; while(g_count++<100) { // здесь выполняются какие-то действия } return 0; }

Однако, здесь есть одна проблема, которую можно обнаружить, посмотрев сгенерированный ассемблерный код. Значение g_count загружается в регистр, увеличивается там и переписывается обратно в g_count. Предположим, g_count равно 40 и Windows прерывает выполнение рабочего потока сразу после того, как он загружает это значение в регистр. Пусть теперь управление получает основной поток и присваивает переменной g_count значение 100 (ожидая, что рабочий поток вслед за этим прекрарит свою работу). При возобновлении рабочий поток увеличивает значение регистра и записывает обратно в g_count число 41, стирая при этом предыдущее значение 100. Итог – цикл рабочего потока не завершился. Допустим, процедура потока модифицируется следующим образом:

…. g_count=0; while(g_count<100) { // здесь выполняются какие-то действия g_count++; } ….

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


Содержание  Назад  Вперед