Применяет ли обращение к указателю типа std :: unique_ptr упорядочение памяти? - PullRequest
0 голосов
/ 31 октября 2019

Допустим, у нас есть глобальный объект типа Wrapper, который имеет std::unique_ptr<MyObject> m_pUnique член, который не равен nullptr. Тогда m_pUnique устанавливается в nullptr в потоке 1, поэтому вызывается деструктор MyObject, и затем поток завершается. После выхода из потока 1 поток 2 вызывает деструктор объекта Wrapper. Вопросы:

  1. Будет ли поток 2 видеть, что m_pUnique равен nullptr после выхода из потока 1? (Я слышал, что при выходе из потока происходит некоторое упорядочение памяти (в данном случае поток 1), но не уверен, увидит ли новое значение указателя поток 2, который читает значение указателя m_pUnique (и НЕ читает значение его внутреннего объекта).)
  2. Если поток 2 не видит, что m_pUnique теперь является nullptr, есть ли вероятность, что деструктор m_pUnique 'MyObject будет вызван снова?

Пример упрощенного кода:

    class Wrapper
    {
    public:
      std::unique_ptr<MyObject> m_pUnique;
    }    

    //Global var created somewhere e.g. in thread 0
    Wrapper* someWrapper = new Wrapper();     
    someWrapper->m_pUnique.reset(new MyObject);
    //...

    //sets m_pUnique to nullptr, which calls MyObject's destructor and then threads exits
    Thread1Func() 
    {
      someWrapper.m_pUnique = nullptr; 
    }  

    //delete Wrapper object after thread 1 has exited  
    Thread2Func()
    {
      delete someWrapper;
    }

Ответы [ 2 ]

0 голосов
/ 10 ноября 2019

Если в потоке вы видите явно магически изменяющееся значение экземпляра класса (которое специально не предназначено для связи потоков), оно может быть только результатом модификации другим потоком, который не был должным образом упорядочен по отношению ко всем потокамэто может прочитать объект, и поведение не определено: компилятор не обязан иметь возможность обрабатывать эти случаи;все может случиться . (Волатильно или не энергозависимо.)

Тот факт, что это экземпляр типа так называемого «умного указателя», не имеет значения.

0 голосов
/ 31 октября 2019

Если поток 2 считывал m_pUnique из someWrapper, то не гарантируется (не подразумевается барьер), что он обнаружит, что m_pUnique изменился, если элемент не помечен как энергозависимый или не атомарный.

Однако, другойкод, который должен повторно проверить объект, запускается при вызове деструктора, поэтому деструктор увидит, что m_pUnique уже имеет значение nullptr, предполагая, что ваш ЦП поддерживает кэш и когерентность ядра. Это предотвращает двойное разрушение целевого объекта.

Без когерентности и дополнительных примитивов синхронизации вы SOL, поскольку в std :: unique_ptr <>.

* нет никаких гарантий безопасности потоков. 1007 * Редактировать : Я хотел бы также отметить, что при наличии нескольких потоков к объекту для записи (удаление является операцией записи), вы должны использовать зЬй :: мьютекс все равно, что делают большую часть вопроса тоо, как любой доступк общему объекту нужно охранять для корректности.

...