Рассмотрим этот класс:
#include <vector>
class A {
private:
std::vector<int> m_vector;
public:
void insertElement(int i) {
m_vector.push_back(i);
}
const std::vector<int>& getVectorRef() const {
return m_vector;
}
};
Метод getVectorRef
поток безопасно?
Возможно ли, что во время возвращения getVectorRef
другой поток появляется и вызывает insertElement
так, что вектор члена изменяется и вызывающий getVectorRef
получает неправильную константную ссылку?
Неужели два квалификатора const (один для вектора, а другой для метода) не имеют значения в контексте безопасности потока?
Функция-член потокобезопасный, ваш интерфейс не. В классе, который разработан как потокобезопасный, вы не можете получить Рекомендации к объектам, которые вы обслуживаете, как будто пользователь хранит эталонную привязку, он может использовать ее, пока выполняется другая операция.
Функция-член является технически поточно-ориентированной. Ссылка на участника — это в основном его адрес, и этот адрес не может измениться. Что бы ни делали другие потоки, ссылка всегда будет ссылаться на один и тот же объект. Но обычно это не ваша главная задача. Реальная проблема заключается в том, что пользователь может сделать с возвратом функции, и в этом случае ответ в основном ничего такого.
Как только пользователь получает ссылку, любой доступ через нее вызовет состояние состязания в сочетании с любой модификацией этого члена в исходном объекте. Вы не можете обеспечить безопасную синхронизацию после того, как откажетесь от ссылок, нет способа сделать потокобезопасный интерфейс из класса, который выдает ссылки.
Если вам нужно сделать поток доступа безопасным, вы можете либо скопировать значение (в критическом разделе), либо предоставить более точные функции, которые будут обрабатывать запросы более высокого уровня от пользователя.
Я бы порекомендовал C ++ параллелизм в действии Энтони Уильямсом за некоторые дискуссии о том, как сделать интерфейсный поток безопасным.
Других решений пока нет …