2013-09-26 11 views
1

В настоящее время я столкнулся с проблемой, что объект (экземпляр), к которому часто обращаются два разных потока, должен быть освобожден. Для меня не имеет значения, какой из двух потоков разрушает экземпляр, но я бы предпочел тот, который также создает его, хотя я думаю, что это вообще не имеет значения.Как безопасно уничтожить объект, к которому часто обращаются два разных потока?

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

Я провел некоторое исследование по этой теме, но я мог просто выяснить, люди говорят: «Зачем нужно удалить объект, который все еще необходим для существования». Но в моем случае он должен перестать быть нужным после того, как кусок кода, который выполняет один поток, решает его уничтожить.

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

+1

Удаление ничем не отличается от любой другой проблемы синхронизации. Используйте мьютекс или что-то в этом роде. – syam

+1

Не использовать [умные указатели] (http://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one)? –

+0

Подождите, пока оба потока не закончатся? – doctorlove

ответ

1

Вы должны были бы двойной окольные, управлять параллельным доступом к данным:

class Object { 
    public; 
    class Data { 
     int get_value() const; 
     void set_value(int); 
    }; 

    class Guard { 
     public: 
     Guard(Nutex& mutex, Data* data) 
     : data(data) 
     { 
      if(! data) throw std::runtime_error("No Data"); 
      mutex.lock(); 
     } 

     ~Guard() 
     { 
      mutex.unlock(); 
     } 

     Data& data() { return *m_data; } 

     private: 
     Data* data; 
    }; 

    class ConstGuard { 
     public: 
     ConstGuard(Mutex& mutex, const Data* data) 
     : data(data) 
     { 
      if(! data) throw std::runtime_error("No Data"); 
      mutex.lock(); 
     } 

     ~ConstGuard() 
     { 
      mutex.unlock(); 
     } 

     const Data& data() const { return *m_data; } 

     private: 
     const Data* data; 
    }; 

    private: 
    friend std::shared_ptr<Object> make_object(const Data&); 
    Object(const Data& data) 
    : data(new Data(data)) 
    {} 

    public: 
    ~Object() 
    { 
     delete data; 
    } 

    /// Self destruction. 
    void dispose() { 
     Guard guard(get()); 
     delete data; 
     data = 0;   
    } 

    // For multiple operations use a Guard. 
    Guard get() { return Guard(mutex, data); } 
    ConstGuard get() const { return ConstGuard(mutex, data); } 

    // For single operations you may provide convenience functions. 
    int get_value() const { return ConstGuard(mutex, data).data().get_value(); } 
    void set_value(int value) { Guard(mutex, data).data().set_value(value); } 

    private: 
    mutable Mutex mutex; 
    data* data; 
}; 

std::shared_ptr<Object> make_object(const Object::Data& data) { 
    return std::make_shared<Object>(data); 
} 

(Примечание: Приведенный выше код просто эскиз, я не был скомпилирован)

Это было длинная история. Короче один [20.7.2.5] shared_ptr атомный доступ:

Concurrent access to a shared_ptr object from multiple threads does not 
introduce a data race if the access is done exclusively via the functions 
in this section and the instance is passed as their first argument. 
  • shared_ptr atomic_load (Const shared_ptr * р);
  • void atomic_store (shared_ptr * p, shared_ptr r);
  • ... Но я не знаком с этими функциями.
0

нить, которая должна не уничтожить объект должен держать его с помощью std::weak_ptr, в течение времени, кроме случаев, когда она активно использует его. В течение этих времен weak_ptr может быть обновлен до std::shared_ptr.

Поток, который должен уничтожить его, теперь может сохраняться до shared_ptr до тех пор, пока он сочтет это необходимым, и отбросить это shared_ptr. Если другой поток имеет только weak_ptr (не активно его использует), объект будет удален. если другой поток также имеет shared_ptr, он удерживается на объекте до завершения операции.