I'm currently writing an RTOS for microcontrollers. The whole thing is written in C++11 - if anyone is interested, and the link to the repository is at the bottom.
Currently I'm writing a class that is a simple data queue for passing objects between threads (or between interrupt handlers and threads or interrupt handlers and other interrupt handlers). Usually I try to follow some common APIs found on other projects, yet I didn't find any example of concurrent queue that has emplace()
function AND supports timeouts.
My general "problem" is that I cannot decide between these two interfaces:
(std::chrono::duration<Rep, Period>
is a templated type, I omit the template boilerplate for clarity)
First version:
template<typename T>
class FifoQueue
{
public:
...
template<typename... Args>
int tryEmplaceFor(std::chrono::duration<Rep, Period>, Args&&... args);
int tryPopFor(T&, std::chrono::duration<Rep, Period>);
int tryPushFor(const T&, std::chrono::duration<Rep, Period>);
int tryPushFor(T&&, std::chrono::duration<Rep, Period>);
...
}
Second version:
template<typename T>
class FifoQueue
{
public:
...
template<typename... Args>
int tryEmplaceFor(std::chrono::duration<Rep, Period>, Args&&... args);
int tryPopFor(std::chrono::duration<Rep, Period>, T&);
int tryPushFor(std::chrono::duration<Rep, Period>, const T&);
int tryPushFor(std::chrono::duration<Rep, Period>, T&&);
...
}
(there will be a second set of these functions with ...Until
suffix - these would use timepoint instead of duration)
The first version follows a "common style" of having the timeout as the last parameter (examples are POSIX message queues, std::condition_variable
, simple queues in any RTOS for microcontrollers). The issue is that it's not possible to have this timeout argument as the last one for tryEmplaceFor() function, because in case of variadic templates "known" arguments must be first (*). So the second version is "consistent" - all functions with timeout have the timeout as the first argument. This variant has an obvious problem of being probably the first example of having timeout as the first argument for such functionality.
Which interface would serve the OS better:
- established standard of having the timeout as the last argument (with exception of
tryEmplaceFor()
andtryEmplaceUntil()
- where it must be the first argument (*))? - consistency - prefer the timeout to be the first argument?
(*) - I know that technically I could have the timeout as last argument for tryEmplaceFor()
and tryEmplaceUntil()
, but I'd rather avoid using such template magic for such simple scenario - doing all these recursive instantiations just to get the last argument seems a bit overkill, especially when I visualize the errors compiler would produce in case user does something wrong...