Что происходит, если поток находится в критическом разделе или входит в критический раздел? - PullRequest
0 голосов
/ 11 ноября 2018

Я пытаюсь лучше понять главу и запутался в том, что происходит, если поток находится в критической секции или входит в критическую секцию.Может кто-нибудь объяснить или дать мне представление о том, что нить претерпевает в таких обстоятельствах?Спасибо.

1 Ответ

0 голосов
/ 11 ноября 2018

Для примера, давайте предположим, что у вас есть массив и несколько потоков, которые читают и записывают в массив;и если разные потоки читают и записывают в массив одновременно, они увидят противоречивые данные, и это вызовет проблемы.Чтобы избежать этих проблем, вы защищаете массив некоторой блокировкой - перед тем, как что-либо делать с массивом, поток получает блокировку массива, а когда он заканчивает использование массива, поток снимает блокировку массива.

Например:

    acquire_array_lock();
    /** Critical section (code that does something with the array) **/
    release_array_lock();

В критическом разделе нет ничего особенного в коде.Он выполняет все, для чего он предназначен (может быть, сортирует массив, может суммировать все числа в массиве, может отображать массив и т. Д.), Используя код, который ничем не отличается от кода, который вы можете использовать, чтобы сделать то же самое в одноммногопоточная система без блокировок.

Единственные специальные части - это код для получения и снятия блокировки.

Существует много типов блокировок (спин-блокировки, мьютексы, семафоры), но все они имеюттот же фундаментальный принцип - когда вы получаете его, у вас есть что-то (например, переменная), чтобы определить, может ли поток продолжить или нет, либо (если поток не может продолжаться), какое-то ожидание или (если поток может продолжить) какие-то изменения, чтобы другие знали, что им нужно ждать;и при выпуске у вас есть что-то, чтобы другие знали, что они могут перестать ждать.

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

Для простейшего вида блокировки (спин-блокировки) у вас может быть просто один флаг "да / нет", чуть-чуть вот так (но не буквально так):

acquire_lock(void) {
    while(myLock == 0) {
        // do nothing then retry
    }
    myLock = 1;
}

release_lock(void) {
    myLock = 0;
}

Однако это не сработает, потому что два или более потоков могут видеть это myLock == 0 одновременно и думать, что они оба могут продолжить (а затем выполнить myLock = 1 после того, как будет слишком поздно).Чтобы это исправить, вам нужен ассемблер или специальная языковая поддержка для атомарных операций (например, специальная функция для «тестирования и установки» или «сравнения и обмена»).

Причина, по которой это называется «спин-блокировкой», заключается в том, что(если поток должен ждать), он тратит время процессора, постоянно проверяя («вращаясь»), чтобы увидеть, может ли он продолжаться.Вместо того, чтобы делать это (чтобы не тратить впустую процессорное время), поток мог сказать планировщику не давать ему никакого процессорного времени, пока не будет снята блокировка;и вот как работает мьютекс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...