Reputation: 1
Unfortunately the cygwin GCC 4.5.3 pthread library implementation doesn't support the POSIX standard function
int pthread_mutex_timedlock(pthread_mutex_t* mutex, struct timespec* abstime);
Has anyone a good idea how to implement a good workaround for this method in a mutex wrapper class? May be using pthread_mutex_trylock()
with a (milliseconds based) nanosleep()
call?
I don't have a good feeling about the latter idea, but anyway the C++ implementation could look like this:
bool MyPosixMutexWrapper::try_lock(const TimeDuration<>& timeout)
{
if(valid)
{
if(timeout == TimeDuration<>::Zero)
{
if(pthread_mutex_trylock(&mutexHandle) == 0)
{
return true;
}
}
else
{
struct timespec now;
clock_gettime(CLOCK_REALTIME,&now);
TimeDuration<> tnow(now);
tnow += timeout;
struct timespec until = tnow.getNativeValue();
#if defined(_POSIX_TIMEOUTS)
if(pthread_mutex_timedlock(&mutexHandle,&until) == 0)
{
return true;
}
#else
long milliseconds = timeout.milliseconds();
while(milliseconds > 0)
{
if(pthread_mutex_trylock(&mutexHandle) == 0)
{
return true;
}
struct timespec interval;
struct timespec remaining;
interval.tv_sec = 0;
interval.tv_nsec = 1000000;
do
{
remaining.tv_sec = 0;
remaining.tv_nsec = 0;
if(nanosleep(&interval,&remaining) < 0)
{
if(errno == EINTR)
{
interval.tv_sec = remaining.tv_sec;
interval.tv_nsec = remaining.tv_nsec;
}
else
{
return false;
}
}
clock_gettime(CLOCK_REALTIME,&now);
tnow = TimeDuration<>(now);
if(tnow >= TimeDuration(until))
{
return pthread_mutex_trylock(&mutexHandle) == 0;
}
} while(remaining.tv_sec > 0 || remaining.tv_nsec > 0);
--milliseconds;
}
#endif
}
}
return pthread_mutex_trylock(&mutexHandle) == 0;
}
Does anyone have a better idea or improvments for this code?
Upvotes: 4
Views: 1913
Reputation: 70482
My suggestion would be to use a pthread_cond_timedwait
to mimic your timed lock. The trick here is that timed_mutex_
is never held for very long, since waiting on timed_cond_
releases the lock. timed_mutex_
is also released immediately after locked_
is set or unset.
struct MutexGuard {
pthread_mutex_t &mutex_;
MutexGuard (pthread_mutex_t &m) : mutex_(m) {
pthread_mutex_lock(&mutex_);
}
~MutexGuard () {
pthread_mutex_unlock(&mutex_);
}
};
struct TimedMutex {
pthread_mutex_t timed_mutex_;
pthread_cond_t timed_cond_;
bool locked_;
TimedMutex ()
: timed_mutex_(), timed_cond_(), locked_(false) {
pthread_mutex_init(&timed_mutex_, 0);
pthread_cond_init(&timed_cond_, 0);
}
~TimedMutex () {
pthread_cond_destroy(&timed_cond_);
pthread_mutex_destroy(&timed_mutex_);
}
int lock (const struct timespec *t) {
MutexGuard g(timed_mutex_);
while (locked_) {
int r = pthread_cond_timedwait(&timed_cond_, &timed_mutex_, t);
if (r < 0) return r;
}
locked_ = true;
return 0;
}
void lock () {
MutexGuard g(timed_mutex_);
while (locked_) {
pthread_cond_wait(&timed_cond_, &timed_mutex_);
}
locked_ = true;
}
void unlock () {
MutexGuard g(timed_mutex_);
locked_ = false;
pthread_cond_signal(&timed_cond_);
}
};
Upvotes: 3