-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixed wait_for_initialization for multiple threads #12
Fixed wait_for_initialization for multiple threads #12
Conversation
@@ -61,7 +61,8 @@ void CarmaClock::update(timeStampMilliseconds current_time) { | |||
// if not initialized then do it and let anyone waiting know | |||
_is_initialized = true; | |||
std::unique_lock lock(_initialization_mutex); | |||
_initialization_cv.notify_one(); | |||
// Notify all blocked threads | |||
_initialization_cv.notify_all(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we choose notify all over one? Is there a scenario that we are testing require it to notify all upon an update?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the conditional variable here can be used to block one our many threads with the wait call. Notify One will only notify a single thread. If multiple threads are waiting on initialization, only 1 will be notified here. The desired behavior is to notify and unblock all threads as shown in my unit test. (https://en.cppreference.com/w/cpp/thread/condition_variable)
@@ -85,6 +86,10 @@ void CarmaClock::wait_for_initialization() { | |||
} | |||
} | |||
|
|||
void CarmaClock::sleep_for(timeStampMilliseconds time_to_sleep) { | |||
sleep_until( _current_time + time_to_sleep); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the sleep_until function, there is a wait call sleepCVPairValue.first->wait(lock);
How does that get notified?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the update function there is a mechanism that notifies each conditional variable based on whether the most recent update is larger or equal to the sleep until value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we added description about those two conditional variables _initialization_cv and sleepCVPair. What they do and why they are needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added addition comments to header with descriptions of the variable used.
Error trying to build with cmake: |
TEST(test_carma_clock, test_sim_time_initialization_multiple_threads) | ||
{ | ||
// try a sim clock | ||
CarmaClock clock(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CarmaClock clock(true);
clock.update(1);
After calling the update (1), the _current_time is 1, and _is_initialized = true. The _initialization_cv will notify_all().
Then thread t sleep for every 150 milliseconds and call update(2), update(3), update(4).
I am assuming the _current_time - 4 by now? Also wait_for_initialization() is not executed as it is only executed when the _is_initialized = false.
Why do we call the
wait_for_initialization() if it is already initialized?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am able to run the unit test and see the _current_time run differently from system clock time. Maybe we have a function to return the _current_time, and ASSERT the _current_time change instead of the system clock time? I guess if we run this carma-clock in simulated time, we care more about the simulated time change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure you understand this unit test. The first thread is sleeping for .15 seconds and then calling update, the other 3 are called immediately. They are blocked for .15 seconds until the update is called from the other thread, which notifies all of them. If you add cout statements you can confirm this in the update method by checking when threads are notified.
In other words all the code inside the 4 threads is executed in parallel.
auto msCount = duration_cast<milliseconds>(after - start).count(); | ||
t.join(); | ||
// should have happened after the update occurred in other thread | ||
EXPECT_NEAR(SYSTEM_SLEEP_TIME, msCount, 5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be 3 instead of 5?
line 195: clock.update(1), wait SYSTEM_SLEEP_TIME, then clock.update(2);
The current_time should be 2. Then clock.sleep_for(1)
, the clock wait for 1 millisecond on top of current time = 2. so the sleep in total may be 3 milliseconds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This 5 is the discrepancy for the unit test. Depending on machine resources this unit test may run faster or slower. The msCount is the difference in machine time for how long the sleep_for command waits. In this case is should wait for SYSTEM_SLEEP_TIME (150 ms) since that is how long it takes for the 1ms time step to be updated. We are leaving a 5ms (machine time) +- buffer to account for resource limitations, especially when run in CI/CD environment (Github actions)
Kudos, SonarCloud Quality Gate passed! |
PR Details
Description
Fix carma-clock object to support multiple threads waiting on initialization. Also added method to sleep_for(milliseconds)
Related GitHub Issue
#10
Related Jira Key
VH-1230
https://usdot-carma.atlassian.net/browse/VH-1230
Motivation and Context
Fix carma-clock which enables time-sync for simulation
How Has This Been Tested?
Unit testing
Types of changes
Checklist: