Я сомневаюсь в использовании объектов из нескольких потоков.
Прежде всего, это не проблема - защитить объект от одновременного доступа с помощью std::lock_guard
или других.
Следующий шагэто объявлять объекты с помощью volatile.
class A
{
public: int val;
};
volatile A a;
Но это приводит к появлению множества новых функций с квалификаторами типов volatile
... int GetVal () volatile;void SetVal () volatile;...
ОК, все это прекрасно работает.
Но как получить доступ к членам stl, например, std::vector
или std::map.
Если я хочу иметь volatilestd::vector<int>
Я запускаю множество ошибок, в то время как stl не определяет какой-либо изменчивый метод.
С этого момента я искал в сети и обнаружил множество «хитростей».В основном с той же идеей на заднем плане: наличие мьютекса для защиты от параллелизма и перемещение volatile
с const_cast
, чтобы сделать стандартный интерфейс доступным.
Как пример этой реализации:
template <typename T>
class PseudoPtr {
public:
PseudoPtr(volatile T& obj, mutex& mtx)
: guard(mtx),
pObj_(const_cast<T*>(&obj))
{ }
~PseudoPtr() { }
// Pointer behaviour
T& operator*() { return *pObj_; }
T* operator->() { return pObj_; }
private:
my_guard<mutex> guard;
T* pObj_;
PseudoPtr(const PseudoPtr&) = delete;
PseudoPtr& operator=(PseudoPtr &) = delete;
};
Имея мой пример класса сверху без квалификаторов volatile
:
class A
{
...
int GetVal();
};
Но если я буду использовать это следующим образом:
volatile A a;
mutex mu;
...
for (;;)
{
PseudoPtr ptr(a, mu); //starts locking the object
if (ptr->GetVal())
{
... do something ...
}
}
Я никогда не будуувидеть любые изменения в объекте a, потому что компилятор мог оптимизировать удаленный доступ, потому что объект volatile был const_cast
, и поэтому оптимизатор ничего не знал о поведении volatile.
Для всех моих собственных классов этоэто не проблема, хотя я мог бы написать все методы volatile
.Но если я хочу использовать контейнер stl, то нет никакого способа получить из них изменчивые экземпляры и использовать его, хотя const_cast
.
ОК, фактический компилятор не так уж сложно оптимизировать (gcc 4.6.1), но есть ли гарантия, что компилятор никогда не выполнит эту оптимизацию?const_cast
сломает volatile
и не const_cast
на volatile
объектах stl не будет работать, в то время как контейнеры stl вообще не имеют изменчивых методов.
Как я думаю все «хитрости», найденные в сети, содержат ошибки, потому что все они игнорируют оптимизатор.
Это касается моих вопросов:
- Я ошибаюсь в своей интерпретации изменчивости иоптимизаторы?
- Существует ли "стандартное" рабочее решение для использования потокобезопасных stl conatiners?
---------------------- после нескольких часов чтения ------------------------
Прежде всего, да, pthread_mutex_lock должен сделатьследующие вещи: * делает доступ к памяти атомарным (это единственное, что я знаю раньше) * гарантирую, что память станет видимой для всех других потоков
ОК, второй был новым для меня!И это приводит к следующему вопросу: как работает трюк?
У библиотеки, которая обеспечивает семантику мьютекса, должна быть возможность сообщить * компилятору, чтобы он остановил выполнение не по порядку * записывает все кэшированные (регистр оптимизирован)) переменные для аппаратного обеспечения * говорят аппаратному обеспечению синхронизировать все аппаратные кэши и т. д.
ОК, хорошо!Но как это работает: Реализация, специфичная для gcc: существует макрос с именем барьером (), который выглядит примерно так:
asm volatile ("" ::: "memory");
Библиотека pthreadgcc включен в glibc / nptl, и каждая функция, которая гарантирует видимость данных для других потоков, просто вызывает макрос барьера или напрямую вызывает встроенный ассемблер или делает что-то подобное.
Если нет недопониманияОпять же, за занавесом стоит простая вещь.
То, что я узнал: volatile в сочетании с блокировкой мьютекса ни в коем случае не полон смысла.
Я пишу этот ответ в надежде, что другие бегутв этой тайне также становится немного меньше суматохи.
Если снова будут ошибки и недоразумения?!: Дайте мне знать!
Спасибо за все ваши ответы!
(Извинитеза редактирование своего поста, чтобы добавить свой собственный вывод, но я не мог добавить собственный ответ к своему посту)