3

I am designing a single-process multi-threaded embedded Linux application. The design includes client-server subsystem where a worker thread receives messages posted by other threads on a POSIX message queue.

I need the queue to exhibit non-blocking send and blocking receive semantics. I can think of several ways to achieve the above: - Creating two separate message queue descriptions for accessing the queue for the sake of send and receive, that is calling mq_open twice. This will be followed by setting the O_NONBLOCK flag of the description that will be used for sending via the queue.

  • Specifying blocking behavior and using mq_timedsend in lieu of mq_send

  • Specifying blocking behavior and calling mq_getattr before mq_send to avoid blocking on send

The first solution is probably the preferred one, however for this to work it must be guaranteed that each call to mq_open creates a new message queue description object (I am also assuming that threads in a process can use multiple such objects to perform operation on the same queue).

POSIX seems to provide such a guarantee (https://pubs.opengroup.org/onlinepubs/009695399/functions/mq_open.html) however Linux documentation does not explicitly say that each call to mq_open creates a new message queue description object.

Is there such a guarantee for Linux?

Thanks,

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
Beni Falk
  • 41
  • 6
  • This sounds like datagram unix domain sockets would be a better fit. Since it's all one process, you can use `socketpair()` to create an anonymous bidirectional pair of sockets to use. Or just a lock free queue data structure. – Shawn Feb 27 '20 at 18:58
  • Have you considered ZeroMQ? Using the `inproc` transport would mean it's avoiding copying data in/out of the kernel, so it could be faster than a Posix message queue. It's also got all the semantics / transports / patterns one could need. – bazza Feb 27 '20 at 20:34

1 Answers1

3

I need the queue to exhibit non-blocking send and blocking receive semantics.

You can use mq_timedsend on a blocking queue with an expired timeout (e.g. abs_timeout{0, 0}), which makes the call return immediately (not block) when the queue is full.


I am designing a single-process multi-threaded embedded Linux application. The design includes client-server subsystem where a worker thread receives messages posted by other threads on a POSIX message queue.

Message queues copy the data into the kernel and back. Communicating between threads in the same process there is no need for that. You can just use a queue with a mutex and a condition variable, that is similar to what the kernel does for you when you use message queues, but using your own queue you would avoid copying data into the kernel and back.

I need the queue to exhibit non-blocking send and blocking receive semantics.

Non-blocking mq_send only means that it doesn't block when the queue is full.

The kernel protects the message queue with a spinlock internally and that spinlock gets locked on mq_send and mq_receive, so that from concurrent data structure point of view POSIX message queue is a blocking data structure.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271