как атомарно инициализировать unique_ptr
От: szag  
Дата: 07.05.15 07:29
Оценка:
Есть unique_ptr<T> ptr который проверяется
if(ptr)
    ptr->foo();

Это все происходит в потоке 1
в потоке 2 в какой-то момент происходит
ptr.reset(new T());

очень не хочется юзать мютекс, так как инициализация происходит только один раз в потоке 2
unique_ptr atomic
Re: как атомарно инициализировать unique_ptr
От: placement_new  
Дата: 07.05.15 08:02
Оценка:
Здравствуйте, szag, Вы писали:

Как вариант можно использовать голые указатели и atomic
http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange

atomic для unique_ptr только как предложение есть.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4260.pdf
Re: как атомарно инициализировать unique_ptr
От: saf_e  
Дата: 07.05.15 08:26
Оценка:
Здравствуйте, szag, Вы писали:

S>Есть unique_ptr<T> ptr который проверяется

S>
S>if(ptr)
    ptr->>foo();
S>

S>Это все происходит в потоке 1
S>в потоке 2 в какой-то момент происходит
S>
S>ptr.reset(new T());
S>

S>очень не хочется юзать мютекс, так как инициализация происходит только один раз в потоке 2

Если задача единорозовая (т.е. обект создается только один раз), тогда можно завести атомарный bool (на x86/64 достаточно volitile bool) и проверяем его, а не потенциально опасный объект.

Если же объект пересоздается более одного раза, то тут наверное без shared_lock не обойтись (ну или городить огород с двухфаторной проверкой)
Re: как атомарно инициализировать unique_ptr
От: uzhas Ниоткуда  
Дата: 07.05.15 08:54
Оценка:
Здравствуйте, szag, Вы писали:

S>очень не хочется юзать мютекс, так как инициализация происходит только один раз в потоке 2


у вас есть какие-то проблемы при текущем подходе без мьютекса? это не легально (все же мьютекс по стандарту нужен), но по факту проблемы могут не проявиться
опишите подробнее
Re[2]: как атомарно инициализировать unique_ptr
От: szag  
Дата: 07.05.15 09:17
Оценка:
Здравствуйте, uzhas, Вы писали:

U>у вас есть какие-то проблемы при текущем подходе без мьютекса? это не легально (все же мьютекс по стандарту нужен), но по факту проблемы могут не проявиться

U>опишите подробнее

проблема потенциальная, но она есть. У нас есть куча киентских сессий, который создаются когда к нам коннектится клиент. Мы им делаем рассылку данных. Часть данных идет в плагины, а они инициализируются в своих потоках в каждой сессии. Соответственно сейчас там стоит такой код
void handler(const data_type& data)
{
    if (ptr)
        ptr->set_data(data);
}


а в другом потоке происходит загрузка плагина (как раз вот этого ptr) и как только он загружен делается
ptr.reset(plugin_raw_ptr);


понятно, что может иногда падать. Объект ptr создается один раз за время жизни сессии и никогда не меняется.
Как исправить не атомарно понятно, хотелось бы как-то атомарно и попроще.
Re[3]: как атомарно инициализировать unique_ptr
От: uzhas Ниоткуда  
Дата: 07.05.15 09:36
Оценка: 6 (2)
Здравствуйте, szag, Вы писали:

S>проблема потенциальная

то есть с проблемой вы еще не столкнулись. и я сомневаюсь, что столкнетесь

S>Как исправить не атомарно понятно, хотелось бы как-то атомарно и попроще.

просто — прикрыть мьютексом. только new лучше не вызывать под мьютексом, может привести к колизиям и уходу в ядро. без колизий не будет ухода в ядро и будет довольно дешево. вызывать метод у объекта тоже лучше не под мьютексом, но тут надо быть аккуратным с владением объекта

std::unique_ptr<T> data;
Mutex m;

//used writer thread
void init()
{
  std::unique_ptr<T> v(new T()); ; // new not under mutex
  if (rawInit(v.get()))
  {
     v.release();
  }
}

bool rawInit(T* v)
{
  MutexLock lock(m);
  if (data)
    return false;
  data.reset(v);
  return true;
}

//reader thread
T* getData()
{
  MutexLock lock(m);
  return data.get();  
}

void useData()
{
  if (T* v = getData())
  {
    v->foo();
  }
}


либо переходите на сырые указатели

std::atomic<T*> data;
std::unique_ptr<T> dataHolder;
//used writer thread
void init()
{
  std::unique_ptr<T> v(new T());
  if (rawInit(v.get()))
  {
     v.release();
  }
}

bool rawInit(T* v)
{
  bool result = data.compare_exchange_strong(nullptr, v);
  if (result)
    dataHolder.reset(v);

  return result;
}

//reader thread
T* getData()
{
  return data;  
}

void useData()
{
  if (T* v = getData())
  {
    v->foo();
  }
}
Re[3]: как атомарно инициализировать unique_ptr
От: Vain Россия google.ru
Дата: 12.05.15 00:45
Оценка:
Здравствуйте, szag, Вы писали:

U>>у вас есть какие-то проблемы при текущем подходе без мьютекса? это не легально (все же мьютекс по стандарту нужен), но по факту проблемы могут не проявиться

U>>опишите подробнее
S>проблема потенциальная, но она есть. У нас есть куча киентских сессий, который создаются когда к нам коннектится клиент. Мы им делаем рассылку данных. Часть данных идет в плагины, а они инициализируются в своих потоках в каждой сессии. Соответственно сейчас там стоит такой код
Т.е. хендлер может выполняться на неинициализированном плагине? Ну тогда это уже не код а дизайн плохой. Пока полная загрузка не пройдёт никакие обработчики вообще не должны вызываться. Кладите данные в очередь и ждите пока не пройдёт загрузка.
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.