Критические секции и возвращаемые значения в C++

Пытаясь создать потокобезопасный контейнерный класс с нуля, я столкнулся с проблемой возврата значений из методов доступа. Например в Windows:

myNode getSomeData( )
{
  EnterCriticalSection(& myCritSec);
  myNode retobj;
  // fill retobj with data from structure
  LeaveCriticalSection(& myCritSec);
  return retobj;
}

Теперь я предполагаю, что этот тип метода вовсе не потокобезопасен, потому что после того, как код освобождает критическую секцию, другой поток может прийти и немедленно перезаписать retobj до того, как первый поток вернется. Итак, каков элегантный способ вернуть retobj вызывающему объекту потокобезопасным способом?


person ThomasMcLeod    schedule 25.07.2012    source источник
comment
Но retobj хранится в стеке? Если он не объявлен «статическим», у вас не должно возникнуть проблем с перезаписью скопированных данных.   -  person    schedule 25.07.2012
comment
Если не происходит что-то странное, retobj должен быть в стеке, и каждый поток должен иметь свой собственный стек. Подобные условия гонки более распространены, когда вы работаете с предварительно выделенной памятью и должны заблокировать доступ, чтобы предотвратить совместное использование.   -  person ssube    schedule 25.07.2012
comment
@inface, хорошо, хорошая мысль, так что пока возвращаемое значение хранится в стеке, все в порядке.   -  person ThomasMcLeod    schedule 25.07.2012


Ответы (2)


Нет, это потокобезопасно, потому что каждый поток имеет свой собственный стек, и именно там находится retobj.

Тем не менее, это, конечно, не безопасно для исключений. Оберните критическую секцию в объект в стиле RAII. Что-то типа...

class CriticalLock : boost::noncopyable {
  CriticalSection &section;

public:
  CriticalLock(CriticalSection &cs) : section(cs)
  {
    EnterCriticalSection(section);
  }

  ~CriticalLock()
  {
    LeaveCriticalSection(section);
  }
};

Применение:

myNode getSomeData( )
{
  CriticalLock  lock(myCritSec);  // automatically released.
  ...
} 
person Roddy    schedule 25.07.2012

Это C++, и retobj имеет автоматический тип хранения, поэтому хранится в стеке.

Каждый поток имеет свой собственный стек, поэтому другой поток не может стереть значение retobj до того, как оно будет возвращено.

person Frédéric Hamidi    schedule 25.07.2012