Я пытаюсь реализовать очередь для нескольких производителей (через прерывание) и одного потребителя (через поток приложения) на встроенной цели в "MpscQueue.h" ниже.
Мне интересно, могу ли я безопасно удалите часть из volatile
, использованную ниже (см. встроенные вопросы). Я также рассмотрел бы использование volatile std::array
вместо C -тиля buffer_[]
, показанного ниже, но я не был уверен, смогу ли я доверять его реализации, чтобы соответствовать цели ниже. Третий вариант - пометить сам объект MpscQueue как volatile
и квалифицировать соответствующие методы volatile
, но не ясно, приведет ли это к тому, что все переменные-члены (и на что они указывают в случае указателей) будут рассматривается как изменчивый.
Есть ли какие-либо указания по этому поводу?
template<typename T, uint32_t depth>
class MpscQueue
{
public:
MpscQueue(void);
bool push(T& t);
bool pop(T* const t);
private:
T volatile buffer_[depth]; // Q1: is volatile unnecessary if never access buffer_[]?
T volatile* const begin_; // Q2: is volatile unnecessary if never access value
T volatile* const end_; // via begin_/end_?
T volatile* head_; // volatile required so that thread always checks value
T volatile* volatile tail_; // Q3: is 'T volatile' required so that ISR accounts
// for other ISRs when setting value?
// Q4: is '* volatile' required so that ISR accounts
// for other ISRs when checking pointer?
};
template<typename T, uint32_t depth>
MpscQueue<T, depth>::MpscQueue(void) :
begin_(&buffer_[0]),
end_(&buffer_[depth - 1]),
head_(begin_),
tail_(begin_)
{}
template<typename T, uint32_t depth>
bool MpscQueue<T, depth>::push(T& t)
{
// "Multiple producer" ISRs can use this function to push at tail
// Pseudo-code: if not full, *(tail_++) = t
}
template<typename T, uint32_t depth>
bool MpscQueue<T, depth>::pop(T* const t)
{
// "Single consumer" thread can use this function to pop at head
// Pseudo-code: if not empty, *t = *(head_++)
}
Редактировать: Чтобы сфокусировать вопрос в правильном направлении, позвольте мне уточнить, что я позаботился о безопасности потоков и здесь это не является частью вопроса.
Поскольку эта очередь является одиночным потребителем, не требуется безопасность потоков на стороне чтения / вывода. Со стороны write / pu sh безопасность потока между прерываниями будет обрабатываться путем установки всех соответствующих прерываний на один и тот же уровень приоритета (в противном случае будет использоваться блокировка).