многопоточное использование пользовательских объектов - PullRequest
3 голосов
/ 21 октября 2011

Я сомневаюсь в использовании объектов из нескольких потоков.

Прежде всего, это не проблема - защитить объект от одновременного доступа с помощью 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 в сочетании с блокировкой мьютекса ни в коем случае не полон смысла.

Я пишу этот ответ в надежде, что другие бегутв этой тайне также становится немного меньше суматохи.

Если снова будут ошибки и недоразумения?!: Дайте мне знать!

Спасибо за все ваши ответы!

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

Ответы [ 3 ]

4 голосов
/ 21 октября 2011

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

2 голосов
/ 21 октября 2011

Я не прав с моей интерпретацией volatile и оптимизаторов?

Да, вы не правы, вам не нужен volatile.Это не Java.Вам необходимо защитить ваши общие объекты мьютексами (или новейшими средствами потоков).Насколько я знаю, "volatile" в C не был создан с учетом потоков.

Есть ли "стандартное" рабочее решение для использования потокобезопасных stat conatiners?1010 * Контейнеры STL не зависят от потоков, это означает, что одновременные чтения не должны быть защищены мьютексами, но если вы пишете, это должно быть.

2 голосов
/ 21 октября 2011

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

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

Наконец, если вы можете переключиться на C ++ 11 (или C ++ 0x), тогдаВы можете использовать все его средства для потоков , включая поточно-ориентированные контейнеры.Все новые версии компиляторов имеют некоторую поддержку этого стандарта, поэтому, если вы не вынуждены работать в какой-либо устаревшей среде, это вариант, который вы, возможно, захотите изучить.

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