Chapter 67 Receive Threads

Connext uses internal threads, known as Receive threads, to process the data packets received via underlying network transports. These data packets may contain meta-traffic exchanged by DomainParticipants for discovery, or user data (and meta-data to support reliable connections) destined for local DataReaders.

As a result of processing packets received by a transport, a Receive thread may respond by sending packets on the network. Discovery packets may be sent to other DomainParticipants in response to packets received. ACK/NACK packets are sent in response to heartbeats to support a reliable connection.

When a DDS sample arrives, the Receive thread is responsible for deserializing and storing the data in the receive queue of a DataReader as well as invoking the on_data_available() DataReaderListener callback (see 40.4 Setting Up DataReaderListeners). Note that in some instances, on_data_available() may be invoked from the Event thread when data is delivered as a result of internal processing, such as the processing of an instance state consistency response (when you are using RECOVER_INSTANCE_STATE_CONSISTENCY in the 47.21 RELIABILITY QosPolicy).

The number of Receive threads that Connext will create for a DomainParticipant depends on how you have configured the QosPolicies of DomainParticipants, DataWriters and DataReaders as well as on the implementation of a particular transport. The behavior of the builtin transports is well specified. However, if a custom transport is installed for a DomainParticipant, you will have to understand how the custom transport works to predict how many Receive threads will be created.

Connext will try to create receive resources1 for every port of every transport on which it is configured to receive messages. The 47.28 TRANSPORT_UNICAST QosPolicy (DDS Extension) for DomainParticipant, DataWriters, and DataReaders, the 48.5 TRANSPORT_MULTICAST QosPolicy (DDS Extension) for DataReaders and the 44.2 DISCOVERY QosPolicy (DDS Extension) for DomainParticipants all configure the number of ports and the number of transports that Connext will try to use for receiving messages.

Generally, transports will require Connext to create a new receive resource for every unique port number. However, this is both dependent on how the underlying physical transport works and the implementation of the transport plug-in used by Connext. Sometimes Connext only needs to create a single receive resource for any number of ports.

When Connext finds that it is configured to receive data on a port for a transport for which it has not already created a receive resource, it will ask the transport if any of the existing receive resources created for the transport can be shared. If so, then Connext will not have to create a new receive resource. If not, then Connext will.

The TRANSPORT_UNICAST, TRANSPORT_MULTICAST, and DISCOVERY QosPolicies allow you customize ports for receiving user data (on a per-DataReader basis) and meta-traffic (DataWriters and DomainParticipants); ports can be also set differently for unicast and multicast.

How do receive resources relate to Receive threads? Connext will create a Receive thread to service every receive resource that is created. If you use a socket analogy, then for every socket created, Connext will use a separate thread to process the data received on that socket.

Connext creates exactly one Receive thread to serve each receive resource. Receive threads are therefore bound to specific receive resources (each Receive thread is bound to exactly one receive resource, and each receive resource is bound to exactly one Receive thread). Consequently, a receive thread lifecycle is tied to the associated receive resource lifecycle: once the receive resource is destroyed, its associated thread will stop running.

So how many threads will Connext create by default–using only the builtin UDPv4 and shared memory transports and without modifying any QosPolicies?

Three Receive threads are created for meta-traffic2:

Two Receive threads created for user data:

  • 2 for unicast (UDPv4, shared memory)
  • 0 for multicast (because user data is not sent via multicast by default)

Therefore, by default, you will have a total of five Receive threads per DomainParticipant. By using only a single transport and disabling multicast, a DomainParticipant can have as few as 2 Receive threads.

Similar to the Database and Event threads, a Receive thread is configured by the 44.7 RECEIVER_POOL QosPolicy (DDS Extension). However, note that the thread properties in the RECEIVER_POOL QosPolicy apply to all Receive threads created for the DomainParticipant.