#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:
То, что вы хотите, невозможно. Причины:
- Вы хотите избежать копий. Это означает, что действительно, вам нужно вернуть ссылку или что-то подобное. В любом случае это означает, что внутренне сохраненный объект должен быть предоставлен вызывающей стороне.
- Вы хотите выполнить любую блокировку внутри вызываемой функции. Это означает, что блокировка и разблокировка должны происходить внутри вызванной вами функции. Вызываемая функция не имеет доступа к вызывающему коду.
В итоге, эти два требования конфликтуют. Вы должны удерживать мьютекс во время доступа к защищенным внутренним данным, но в то же время вы хотите предоставить доступ к этим данным вызывающей стороне.
Кстати: Это не ваш вопрос, но вам, вероятно, будет интересно, как это решить. Первое, на что следует обратить внимание, это то, что вы оптимизируете с учетом вашего требования не копировать. В качестве альтернативы, если доказано, что это (!) является узким местом, оптимизируйте копирование вместо этого, например, используя идиому handle / body с неизменяемым телом. Кроме того, мне интересно, чего вы хотите достичь, оптимизируя область блокировки мьютекса. Это также может быть антишаблоном многопоточности.