Чтение и запись мьютекса в системе получения постоянной ссылки (с использованием Qt)

#c #multithreading #qt #mutex

#c #многопоточность #qt #мьютекс

Вопрос:

Я использую следующую схему в своей программе Model-View-Controller:

 class model{

public
const submodelAamp; getSubModA() const;
const submodelBamp; getSubModB() const;

private:
submodelA _submod_a;
submodelA _submod_b;

}
  

Один поток будет выполнять запись в подмодели, используя соединения с сигнальным слотом. Многие потоки будут считывать данные из этих подмоделей.

Поэтому я хотел бы использовать блокировку чтения и записи. Однако я хочу избежать следующего:

 ...
_model.getSubModA().getQReadWriteLock().lockForRead();
int foo = _model.getSubModA().getFoo();
_model.getSubModA().getQReadWriteLock().unlock();
...
  

Как вы можете видеть, это излишне многословно.

Я хотел бы сделать просто

 int foo = _model.getSubModA().getFoo();
  

Средства получения подмоделей должны возвращать ссылки const, например, чтобы избежать ненужных копий.

Возможно ли каким-либо образом инкапсулировать эту функциональность в получателе?

 const model::submodelAamp; getSubModA() const{

_submod_a.getQReadWriteLock().lockForRead();
return _submod_a;

}
  

Очевидно, проблема здесь в том, что я не могу разблокировать после возврата. Я думал обойти это, включив локальную переменную со ссылкой на блокировку readwrite, которая разблокировала бы ее в своем деструкторе, но я беспокоюсь, что это может каким-то образом привести к неопределенному поведению, поскольку оно возвращается по ссылке.

Существуют ли какие-либо шаблоны или практики, которые решают эту проблему?

Ответ №1:

То, что вы хотите, невозможно. Причины:

  1. Вы хотите избежать копий. Это означает, что действительно, вам нужно вернуть ссылку или что-то подобное. В любом случае это означает, что внутренне сохраненный объект должен быть предоставлен вызывающей стороне.
  2. Вы хотите выполнить любую блокировку внутри вызываемой функции. Это означает, что блокировка и разблокировка должны происходить внутри вызванной вами функции. Вызываемая функция не имеет доступа к вызывающему коду.

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

Кстати: Это не ваш вопрос, но вам, вероятно, будет интересно, как это решить. Первое, на что следует обратить внимание, это то, что вы оптимизируете с учетом вашего требования не копировать. В качестве альтернативы, если доказано, что это (!) является узким местом, оптимизируйте копирование вместо этого, например, используя идиому handle / body с неизменяемым телом. Кроме того, мне интересно, чего вы хотите достичь, оптимизируя область блокировки мьютекса. Это также может быть антишаблоном многопоточности.