Sign in to follow this  
Prune

(Linux) mutex timed lock vs timed condition wait

Recommended Posts

Prune    224
Why use one over the other? Both seem to accomplish the same thing. Which one would have lower overhead? I'm just using it to sleep a log-flushing thread for periodic times (until signaled by a full log buffer or log destructor). The main thing for me is to guarantee there will be no busy wait.

Share this post


Link to post
Share on other sites
erissian    727
mutex_timedlock is signal safe as well as thread safe, while cond_timedwait is only thread safe. Also cond_timedwait unlocks a mutex and then waits for a condition, while mutex_timedlock takes ownership of a mutex. Entirely different.

Share this post


Link to post
Share on other sites
Prune    224
That still doesn't tell me which one to use.

I want to sleep a thread until a timeout or until I want it to wake up. Both of these accomplish this--the timed condition wait when the condition is met or a timeout, and the timed lock until the mutex is unlocked or a timeout.

Which one has less overhead? I also assume at least in NPTL neither will busy-wait.

Share this post


Link to post
Share on other sites
erissian    727
If you want to resume the thread, use the cond_timedwait. It doesn't sound like you need to take control of a mutex, which is what mutex_timedlock is for.

Share this post


Link to post
Share on other sites
Prune    224
But the condition functions take a mutex as an argument...

Here's the relevant code, maybe you can kindly explain how it should really be done:

shared_ptr<pthread_t> Log::TimerOn(int const sec)
{
if (Acquire(_delay)) return _thread;
Release(_delay, sec);
pthread_mutex_lock(_timeout.get());
_thread.reset(new pthread_t);
if (!_thread || pthread_create(_thread.get(), 0, Timer, this)) Release(_delay, 0);
return _thread;
}

bool Log::TimerOff(void)
{
// TODO: check for values of thread, timeout, etc.
if (!Acquire(_delay)) return true;
Release(_delay, 0); // Timer() loop condition is _delay != 0
timespec tDelay;
tDelay.tv_sec = 0;
tDelay.tv_nsec = 200000000;
for (int i = 0; Acquire(_cycle) && i < 10; ++i) // Timer() is currently executing a Flush() while _cycle is set; give it more time
{
pthread_mutex_unlock(_timeout.get());
pthread_delay_np(&tDelay);
}
if (Acquire(_cycle)) // Timer() thread still hasn't quit; terminate it
{
pthread_cancel(*_thread);
return false;
}
pthread_mutex_unlock(_timeout.get());
return true;
}

void *Log::Timer(void *obj)
{
SetThreadName("Log timer"); // For Windows debugger
Log *log(static_cast<Log *>(obj));
timespec tDelay;
tDelay.tv_nsec = 0;
while (Acquire(log->_delay))
{
Release(log->_cycle, true);
// TODO: Make sure target system does not use busy waiting before using timer
// TODO: Use relative time when pthread_mutex_timedlock_np() available
tDelay.tv_sec = static_cast<long>(time(0)) + log->_delay;
pthread_mutex_timedlock(log->_timeout.get(), &tDelay);
if (log->_ind >= 0) log->Flush();
Release(log->_cycle, false);
}
return 0;
}


(Timer() is a static member; Acquire() and Release() just wrap volatile access and memory barriers; _thread, _lock, and _timeout are shared_ptr holding the corresponding pthread types)

Share this post


Link to post
Share on other sites
Dmytry    1151
Prune:
In similar situation, I used semaphore (with wxWidgets).
I believe it uses sem_timedwait . The idea is to create a semaphore initialized to zero, and use sem_timedwait to sleep , and sem_post from other thread to wake it up. I made custom thread class with Sleep function that does this, so that I can wake up sleeping thread when i want to exit it quickly.
I don't remember exactly why I used semaphores, probably because semaphores seem to be the right tool for that job, the wait and post semantics is precisely what you seem to need.

With mutex, you would have to lock it first, and unlock to wake up the thread, then the thread would lock it again... and you'll be locking mutex from one thread and unlocking from another, which might be a no-no (mutex stands for mutual exclusion, and normally you lock then unlock it from same thread. It may be optimized for such use (or not be)).
cond_timedwait requires to create both condition variable and mutex, and looks more complicated than sem_timedwait.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this