mercredi 1 novembre 2023

Single Producer Single Consumer queue optimization advice

OS : VxWorks 22.09
Project Type : Real Time Process (RTP)
CPU : Intel 11th Generation i7-1185GRE (4 CPU 8 Threads)

I'm working on a Hard Real Time low latency system.
I have a Single Producer Single Consumer problem.

Data is produced by the callback function on the read thread (Ethernet and Serial Ports threads).
The data is consumed by main thread.

Pseudo Code :

typedef struct EthernetData
{
     std::string ip;
     std::uint16_t portNumber;
     std::string data;
}ethernet_data_t;

std::queue<ethernet_data_t> ethernet_queue;
boost::lockfree::spsc_queue<ethernet_data_t, boost::lockfree::capacity<10> > spsc_queue;

Ethernet Callback
void on_receive_ethernet(const std::string &ip, std::uint16_t portNumber, const std::string &data)
{
    ethernet_data_t data {ip, portNumber, data};
    ethernet_queue.push(data)
}

Main Thread

void run(void)
{
    while(1)
    {
        if(ethernet_queue.empty() == false)
        {
            //Process Ethernet Data
        }
        if(SerialPort1_queue.empty() == false)
        {
            //Process SerialPort1 Data
        }
        if(SerialPort2_queue.empty() == false)
        {
            //Process SerialPort2 Data
        }
        
        ...
    }
}

I am inclining towards boost::lockfree::spsc_queue after reading the bellow

Performance of Non-Blocking Data Structures

Lock-free data structures will be a better choice in order to optimize the latency of a system or to avoid priority inversion, which may be necessary in real-time applications. In general we advise to consider if lock-free data structures are necessary or if concurrent data structures are sufficient. In any case we advice to perform benchmarks with different data structures for a specific workload.

I have few questions:

  1. Will the boost::lockfree::spsc_queue use atomic instruction instead of guards for complex data type like structure defined above for boost::lockfree::spsc_queue? I ask this because the lock free documentation states Instead of relying on guards, non-blocking data structures require atomic operations (specific CPU instructions executed without interruption).
  2. In the answer https://stackoverflow.com/a/53854518/6319901, it states in single producer and singe consumer don't need mutex. If I just check if the queue is empty in main thread in side the while loop (without mutex) will it work or will I suffer some synchronization problem. If not wouldn't it be preferable to use std::queue without any guards (mutex)
  3. I have on an average 5 such queues on each RTP. I have 6 such RTPs. Will this cause any performance bottleneck.
  4. Is checking queue if empty inside while loop advisable. I chose this design pattern to avoid latency.
  5. Is their any better alternatives available?

Aucun commentaire:

Enregistrer un commentaire