Skip to content
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

Fix no composite frame on playback (from Nir) #9210

Merged
merged 10 commits into from
Jun 13, 2021

Conversation

maloel
Copy link
Collaborator

@maloel maloel commented Jun 12, 2021

  • add actual matchers to playback device
  • live-test issues with playback
  • added !mayfail to frame-number syncing test for stability
  • added waiting_on<> in utilities/time/waiting-on.h, with unit-test
  • rework dispatcher::flush()

Tracked on [DSO-16888]

@maloel maloel requested review from ev-mp, aangerma and Nir-Az June 12, 2021 14:46
Copy link
Collaborator

@ev-mp ev-mp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see inline

Comment on lines +18 to +19
template< class T >
class waiting_on
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class seem to mimic std::future, why is it needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we're not using std::future... and the whole mechanism of the dispatcher is written without it.
Perhaps we can refactor this class to use it later, but for now... no.

Comment on lines +85 to +86
if( auto wait_state = still_alive() )
wait_state->signal( t );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The operation needs to be atomic to avoid race cond.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole class is meant to be used in a master-slave kind of relationship: one thread running one function (and not multiple threads running one function). You're waiting on something to happen with a timeout. That's all.

The use-case of multiple threads all trying to signal the same waiting object is still possible -- this class does not decide for the user what the synchronization mechanism is. The user writes the lambda, which can worry about synchronization if it needs it. I don't think it's the job of the class.

I'll add the above to the class comment.

src/dispatcher.cpp Show resolved Hide resolved
// break;
// }
template < class U, class L >
void wait_until( U const& timeout, L const& pred )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think its better if wait_until will return bool - true = pred , false =timeout

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer with no return value to make the code more readable


// Wake up the local function (which is using wait_until(), presumable) with a new
// T value
void signal( T const& t ) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider to change it to safe_signal() , I think its clear what is the added value of this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing makes it safe... it's just a convenience

{
}

operator T &() { return _value; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want to enable to change the value without signal?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, the set-and-signal function is just a convenience function

// Convert to the in-thread representation
in_thread_ in_thread() const { return in_thread_( *this ); }

operator T const &() const { return _ptr->_value; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't use operator T &() of wait_state_t?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to *_ptr instead of _ptr->_value

// struct value_t { double x; int k; };
// waiting_on< value_t > output({ 1., -1 });
// output->x = 2.;
T * operator->() { return &_ptr->_value; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No easy syntax that can be used here

// waiting_on< value_t > output({ 1., -1 });
// output->x = 2.;
T * operator->() { return &_ptr->_value; }
T const * operator->() const { return &_ptr->_value; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

std::mutex m;
// Following will issue (from CppCheck):
// warning: The lock is ineffective because the mutex is locked at the same scope as the mutex itself. [localMutex]
std::unique_lock< std::mutex > locker( m );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to lock the mutex on signal() too

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's up to the user to write the lambda with concurrency in mind, if that's what's needed (for example, in dispatcher.cpp it's not needed)

//Go over the sensors and stop them
size_t active_sensors_count = m_active_sensors.size();
for (size_t i = 0; i<active_sensors_count; i++)
std::vector<std::shared_ptr<playback_sensor>> playback_sensors_copy;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment why do we need local copy of playback_sensors

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Stopping the sensor will call another function which will remove the sensor from the
// list of active sensors, which will cause issues -- so we copy it first


auto i1 = output->i.load();
CHECK( i1 >= 10 ); // the thread is still running!
CHECK( i1 < 16 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how can you be sure i1 < 16 if the thread is still running?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I expect it to notify at 10, 16 would be 6*50=300ms later.
It's possible for it to fail, but very unlikely: it would mean the thread continued but this thread was paused for that amount of time...

//std::cout << "i2= " << i2 << std::endl;

// Wait until it's done, ~30x50ms = 1.5 seconds total
REQUIRE( output->i < 30 );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here the thread keep running and i can be equal to 30, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same kind of expectation: the other thread has slept between iterations, but this thread has not. For this to fail, something strange must happen.

Copy link
Collaborator

@ev-mp ev-mp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved

@ev-mp
Copy link
Collaborator

ev-mp commented Jun 13, 2021

Note that it is still not targeted for dev

@maloel maloel merged commit 522605c into IntelRealSense:concsync Jun 13, 2021
@maloel maloel deleted the nirs2 branch December 22, 2021 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants