I am using fastdds publisher, following code to publish data. getMatchedStatus() returns publication_matched callback status
if subscriber is matched, getMatchedStatus() = 1
if no matching subscriber, getMatchedStatus() = 0
if subscriber shutdown after reading data, getMatchedStatus() = -1
void publish(){
while (getMatchedStatus() == 0) { **// waiting for a subscriber** what is the best way to replace this sleep?
std::this_thread::sleep_for(std::chrono::milliseconds(250));//250ms
}
while (getMatchedStatus() == 1) {
writer_.write(&Topic);
if (getMatchedStatus() == -1) { // Check subscriber unmatched status
break;
}
}
}
I need a proper way or best way to wait for a matching subscriber.....
is using std::this_thread::sleep_for(std::chrono::milliseconds(250));//250ms okay? for prodcution code?
the 1st while loop should wait without making the processor busy as well...
I can think of three solutions: Sleeps, Condition Variables, and WaitSets. Using sleeps, however, seems to me like the less efficient one (but probably the easiest to implement):
As a general rule: it is not advisable to use sleeps to wait events. By using sleeps, you lose the control on your thread, and you depend on a fixed value rather than waiting for a real event. This makes you awake more times than required, and do not awake when needed. However, if your application/library is not real-time oriented and does not require efficiency, it is always an option.
Using the class std::condition_variable
under <condition_variable>
will provide and easy and efficient way to wait on a publication match, and awake any other thread.
There is an example in Fast-DDS repository that uses this exact method in order for the publisher to wait until a subscriber is matched: https://github.com/eProsima/Fast-DDS/tree/master/examples/C%2B%2B/DDS/BasicConfigurationExample .
The solution will look like this:
// Your publish method
void publish(){
// Wait in condition variable till predicate is true
std::unique_lock<std::mutex> lck(wait_matched_cv_mtx_); // Internal DataWriter mutex
wait_matched_cv_.wait(lck, [this] {
return matched(); // Implement matched method in DataWriter or any method similar
});
// At this point it is sure that DataWriter has matched
while (getMatchedStatus() == 1) {
writer_.write(&Topic);
if (getMatchedStatus() == -1) { // Check subscriber unmatched status
break;
}
}
}
// DataWriterListener overrided method (this should be implemented by the listener passed to the DataWriter when created.
void HelloWorldPublisher::PubListener::on_publication_matched(
eprosima::fastdds::dds::DataWriter*,
const eprosima::fastdds::dds::PublicationMatchedStatus& info) {
if (info.current_count_change == 1) {
std::unique_lock<std::mutex> lck(wait_matched_cv_mtx_);
publisher_condition_variable_.notify_all();
}
}
NOTE: it is strongly recommended to use mutex and predicates when using condition variables. Check following post: predicate for condition variable
There is a recent feature in Fast-DDS called WaitSets that are used for this exact propose. This allows to wait for an event, as a message received or an entity match. What it actually does is wrap the std::condition_variable
class so it could be used with more sugary methods.
Check Fast-DDS documentation in order to learn how to use them: https://fast-dds.docs.eprosima.com/en/latest/fastdds/dds_layer/core/waitsets/waitsets.html .