I use freeRTOS V10.4.3. I have un unexpected behavior with a queue. In an interrupt routine (r_elc_isr_port1) I send an item to a queue (EventQueue) by xQueueSendToBackFromISR. In a task (cDigitalInputPwmTask::run) I receive the item from the queue with xTicksToWait = portMAX_DELAY.
I expect that xQueueReceive is blocked as long as no items are entered into the queue. I added counters to see if this true in my case. The FillCount counter is incremented, each time an item is sent to the queue and decrement each time an item is received from the queue. To be sure that the queue does not get full and items are not put to the queue i check with FullCount coounter.
What I find is thet the FillCount gets negatic after a while and grows slowly into more negativ. The FullCount stays zero (as expected, queue has size of 50 items and at the most less than 10 are in the queue at a time).
Than I added the additional EmptyCount counter after the call of xQueueReceive, to make sure, that the xQueueReceive only unblockes when their is an item in it. Thsi counter also stays zero.
I attached the source file doing all described above.
DigitalInputPwmTask.cpp (7.0 KB)
Has anyone an idea what can be wrong?
A few observations in the code:
- The fillcount is defined as int “int FillCount;”. Usually, “unsigned int” is used for counters.
- There is equal to zero check when the count is decremented.
The FillCount counter is made to see if in the long term as many items are received as sent to the queue. If more items are received from the queue as sent to it the fillcount must get negativ. So that’s why the count must be declared signed and it may not be decremented only as long as it is greater zero.
The point is not the counter gets negative. The point is that more items seem to be received then sent to the queue. In this is shown in the counter getting negative.
I’d propose to use either an atomic counter
std::atomic<int> if already supported by your compiler or 2
volatile (unsigned) counters (++send/++receive) to evaluate the difference.
Inc/decrementing a normal
int is a non-atomic operation and can produce wrong results due to race conditions.
I agree. It’s better to try with an atomic counter and evaluate.
I agree about the counter, a q&d solution would be a critical section in the task code (of course unneeded in the isr).
The code looks ok except it looks as if your ISR may be enabled before the queue is created. If that is the case, it would typically result in a fault, though, not in the behavior you see.
Ok, I agree to the atomic argument. I tested volatile, does not help.
std::atomic<int> results in a compiler error. Using portENTER_CRITICAL() solved my problem, which seems to me to right method.
Thanks everyone for help.