Означает ли const поточно-ориентированный в C ++ 11?

Я слышу это const средства потокобезопасной в C ++ 11. Это правда?

Это значит const теперь эквивалент Джава«s synchronized?

Они заканчиваются ключевые слова?

112

Решение

Я слышу это const средства потокобезопасной в C ++ 11. Это правда?

это в некотором роде правда…

Это то, что Стандартный язык должен сказать о безопасности потока:

[1.10 / 4]
Две оценки выражений конфликт если один из них изменяет ячейку памяти (1.7), а другой обращается или изменяет ту же ячейку памяти.

[1.10 / 21]
Выполнение программы содержит гонка данных если он содержит два конфликтующих действия в разных потоках, по крайней мере одно из которых не является атомарным, и ни одно из них не происходит раньше другого. Любая такая гонка данных приводит к неопределенному поведению.

что является не чем иным, как достаточным условием для гонка данных происходить:

  1. Есть два или более действий, выполняемых одновременно с данной вещью; а также
  2. По крайней мере, один из них — запись.

Стандартная библиотека опираясь на это, пойдем немного дальше:

[17.6.5.9/1]
Этот раздел определяет требования, которым должны соответствовать реализации, чтобы предотвратить гонки данных (1.10). Каждая стандартная библиотечная функция должна отвечать каждому требованию, если не указано иное. Реализации могут предотвратить скачки данных в случаях, отличных от указанных ниже.

[17.6.5.9/3]
Стандартная библиотечная функция C ++ не должна прямо или косвенно изменять объекты (1.10), доступные для потоков, отличных от текущего потока, если к объектам не обращаются прямо или косвенно через функциюConst аргументы, в том числе this,

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

  1. Состоят исключительно из чтения — то есть, нет записи -; или же
  2. Внутренне синхронизирует пишет.

Если это ожидание не выполняется для одного из ваших типов, то используйте его прямо или косвенно вместе с любым компонентом Стандартная библиотека может привести к гонка данных. В заключение, const значит потокобезопасной от Стандартная библиотека точка зрения. Важно отметить, что это всего лишь контракт и это не будет выполняться компилятором, если вы нарушите его, вы получите неопределенное поведение и ты сам по себе. Будь то const присутствует или нет не повлияет на генерацию кода — по крайней мере, не в отношении гонки данных—.

Это значит const теперь эквивалент Джава«s synchronized?

нет. Не за что…

Рассмотрим следующий чрезмерно упрощенный класс, представляющий прямоугольник:

class rect {
int width = 0, height = 0;

public:
/*...*/
void set_size( int new_width, int new_height ) {
width = new_width;
height = new_height;
}
int area() const {
return width * height;
}
};

член-функция area является потокобезопасной; не потому что его const, но потому что он состоит исключительно из операций чтения. Нет вовлеченных записей, и для гонка данных происходить. Это означает, что вы можете позвонить area из столько потоков, сколько вы хотите, и вы будете получать правильные результаты все время.

Обратите внимание, что это не значит, что rect является потокобезопасной. На самом деле, легко увидеть, как если бы звонок area должно было произойти в то же время, что вызов set_size на данный rect, затем area может в итоге вычислить свой результат на основе старой ширины и новой высоты (или даже искаженных значений).

Но это нормально, rect не const так что его даже не ожидается потокобезопасной в конце концов. Объект объявлен const rectс другой стороны, будет потокобезопасной поскольку никакие записи невозможны (и если вы рассматриваете const_castчто-то первоначально заявленное const тогда вы получите неопределенное-поведение и это все).

Так что же это значит?

Давайте предположим — ради аргумента — что операции умножения чрезвычайно дороги, и мы лучше их избегать, когда это возможно. Мы могли бы вычислить область, только если она запрашивается, и затем кэшировать ее на случай, если она будет запрошена снова в будущем:

class rect {
int width = 0, height = 0;

mutable int cached_area = 0;
mutable bool cached_area_valid = true;

public:
/*...*/
void set_size( int new_width, int new_height ) {
cached_area_valid = ( width == new_width && height == new_height );
width = new_width;
height = new_height;
}
int area() const {
if( !cached_area_valid ) {
cached_area = width;
cached_area *= height;
cached_area_valid = true;
}
return cached_area;
}
};
[Если этот пример кажется слишком искусственным, вы могли бы мысленно заменить int по очень большое динамически размещаемое целое число который по своей сути не потокобезопасной и для которых умножения являются чрезвычайно дорогостоящими.]

член-функция area больше не потокобезопасной, это делает записи сейчас и не внутренне синхронизированы. Это проблема? Призыв к area может случиться как часть копия-конструктор другого объекта, такого конструктор мог быть вызван какой-то операцией на стандартный контейнер, и в этот момент стандартная библиотека ожидает, что эта операция будет вести себя как читать в отношении гонки данных. Но мы делаем записи!

Как только мы положим rect в стандартный контейнер —прямо или косвенно — мы вступаем в контракт с Стандартная библиотека. Чтобы продолжать делать записи в const пока мы выполняем этот контракт, нам нужно внутренне синхронизировать эти записи:

class rect {
int width = 0, height = 0;

mutable std::mutex cache_mutex;
mutable int cached_area = 0;
mutable bool cached_area_valid = true;

public:
/*...*/
void set_size( int new_width, int new_height ) {
if( new_width != width || new_height != height )
{
std::lock_guard< std::mutex > guard( cache_mutex );

cached_area_valid = false;
}
width = new_width;
height = new_height;
}
int area() const {
std::lock_guard< std::mutex > guard( cache_mutex );

if( !cached_area_valid ) {
cached_area = width;
cached_area *= height;
cached_area_valid = true;
}
return cached_area;
}
};

Обратите внимание, что мы сделали area функция потокобезопасной, но rect все еще не потокобезопасной. Вызов area происходит в то же время, что вызов set_size может все еще в конечном итоге вычислить неправильное значение, так как назначения width а также height не защищены мьютексом.

Если бы мы действительно хотели потокобезопасной rectмы бы использовали примитив синхронизации для защиты без потокобезопасной rect,

Они заканчиваются ключевые слова?

Да. У них кончились ключевые слова с первого дня.


Источник: Ты не знаешь const а также mutableХерб Саттер

126

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]