Это правило о волатильном использовании строгое? - PullRequest
4 голосов
/ 12 ноября 2010

Я видел это предложение:

общее правило: если у вас есть переменные примитивного типа, которые должны совместно использоваться несколькими потоками, объявите эти переменные volatile

из этой статьи и этого предложения:

В общем случае любые данные, которые могут быть асинхронно недатированными, должны быть объявлены как изменчивые.

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

Ответы [ 8 ]

12 голосов
/ 12 ноября 2010

Я помню, когда эта статья была опубликована, и я помню бесконечные дискуссии, которые затем велись на comp.lang.c ++., Модерируемой.

IIRC, Андрей перехватывает ключевое слово volatile , чтобы использовать его для различения различных перегрузок функций. (См. эту статью Скотта Мейерса для другой такой идеи.) То, что он делает, блестяще, в том, что это позволяет компилятору чтобы поймать вас, если вы испортите защищенный и незащищенный доступ к объектам (очень похоже на то, как компилятор ловит вас, если вы попытаетесь изменить константу). Но помимо того, что это помогает вам, это не имеет ничего общего с фактической защитой одновременного доступа к объектам .

Проблема только в том, что 90% людей имеют один взгляд на статью, и они видят только volatile и "темы" в той же статье . В зависимости от своих знаний они либо делают неверный вывод о том, что volatile хорош для потоков (вы, кажется, так и сделали), либо они кричат ​​на него, заставляя других рисовать неправильные выводы.
Кажется, очень немногие люди действительно могут полностью прочитать статью и понять, что он на самом деле делает.

11 голосов
/ 12 ноября 2010

Я не могу говорить о фактическом сценарии асинхронного доступа, поскольку я не слишком хорош в многопоточности, но то, что делает модификатор volatile, говорит компилятору:

«Послушайте, это может измениться в любое время, так что не кешируйте его, не помещайте в регистр и не делайте ничего сумасшедшего, хорошо?»

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

Редактировать: В качестве потенциального примера, тот, который не включает в себя многопоточность (но, действительно, включает в себя исключительно запутанный код;),Вот случай, когда volatile имеет важное значение:

volatile bool keepRunning = true;
void Stuff() {
    int notAPointer = 0;

    notAPointer = (int)(&keepRunning); //Don't do this! Especially on 64-bit processors!

    while(keepRunning) {
        *(bool*)(notAPointer) = false;
    }

    printf("The loop terminated!");
}

Без этого модификатора volatile компилятор может сказать: «Эй, keepRunning никогда не изменяется, поэтому мне даже не нужно генерировать код, который его проверяет!»,когда на самом деле мы просто секретно модифицируем его.

(На самом деле, это, вероятно, все еще будет работать на неоптимизированной сборке. И, возможно, это все еще будет работать, если компИлер умный и замечает, что указатель взят.Но принцип тот же)

3 голосов
/ 12 ноября 2010

Читать это .Volatile не имеет ничего общего с многопоточностью.

2 голосов
/ 13 ноября 2010

Я бы сказал, что в теории эти правила абсолютно верны, и переменная необходима каждый раз, когда к переменной обращаются 2 потока.(Даже при использовании мьютексов они не препятствуют оптимизации компилятора.) Но на практике компиляторы достаточно хорошо распознают ситуации, когда переменная может быть изменена вне конкретной функции, чтобы ее значение не кэшировалось в регистрах.В большинстве случаев volatile не требуется.

Однажды я провел некоторое тестирование в MSVC, проверив выходные данные ассемблера на различные ситуации, и все, что нужно для предотвращения кэширования переменной, - это заставить другую функцию записывать в ту жепеременная или принимая его адрес.Глобальные переменные никогда не оптимизировались, если не была включена «оптимизация всей программы» (поэтому компилятор может быть уверен, что переменная не изменена в других единицах перевода).

2 голосов
/ 12 ноября 2010

Я бы предложил значительно более строгое, но очень полезное правило: если вы не понимаете, что именно делает volatile, не используйте его.Вместо этого используйте lock.Если вы точно не понимаете, что делает lock и как его использовать, не используйте многопоточность.

2 голосов
/ 12 ноября 2010

Чтобы проконтролировать ответ Майка, это полезно в таких случаях (глобальные переменные используются для избежания сложности в этом примере):

static volatile bool thread_running = true;

static void thread_body() {
    while (thread_running) {
        // ...
    }
}

static void abort_thread() {
    thread_running = false;
}

В зависимости от того, насколько сложным является thread_body, компилятор может выбрать кэширование значения thread_running в регистре при запуске потока, что означает, что он никогда не заметит, если значение изменится на false. volatile заставляет компилятор выдавать код, который будет проверять фактическую переменную thread_running в каждом цикле.

0 голосов
/ 13 ноября 2010

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

0 голосов
/ 12 ноября 2010

Аналогично, стандарт C ++ не определяет, как должен работать volatile, вы должны посмотреть, что конкретный компилятор делает для конкретной платформы.Также volatile немного неуловимо и зависит от компилятора и модели памяти целевой платформы.Замки более интуитивно понятны в использовании.

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