I want to protect a function from multithreaded access. For that purpose I am using a pthread_mutex_t
mutex. I try to lock it in the beginning of a function, then execute the function, then release it again. If the mutex is in use it should wait for at maximum 60 seconds for it to be come available. If after that it is still not available, the function should fail.
The problem I'm having is it that pthread_mutex_timedlock
seems to completely ignore the timeout value I'm giving it. Although I specify a timeout of 60 seconds, if the lock is taken, the function returns immediately with the error code ETIMEDOUT
-- without actually waiting.
Here is a minimal example which reproduces the problem. In this case it does not matter whether I'm using recursive or non-recursive mutexes, since I'm not trying to lock them multiple times from the same thread.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
pthread_mutex_t lock; /* exclusive lock */
//do some work to keep the processor busy..
int wut() {
int x = 0;
for(int i=0; i < 1024*1024*1024; i++)
x += 1;
return x;
}
void InitMutex(){
/*pthread_mutexattr_t Attr;
pthread_mutexattr_init(&Attr);
pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &Attr);*/
pthread_mutex_init(&lock, NULL);
}
//lock mutex, wait at maximum 60 seconds, return sucesss
int LockMutex() {
struct timespec timeoutTime;
timeoutTime.tv_nsec = 0;
timeoutTime.tv_sec = 60;
printf("Nanoseconds: %lu, seconds %lu\n", timeoutTime.tv_nsec, timeoutTime.tv_sec);
int retVal = pthread_mutex_timedlock(&lock, &timeoutTime);
printf("pthread_mutex_timedlock(): %d\n", retVal);
if(retVal != 0) {
const char* errVal = NULL;
switch(retVal) {
case EINVAL: errVal = "EINVAL"; break;
case EAGAIN: errVal = "EAGAIN"; break;
case ETIMEDOUT: errVal = "ETIMEDOUT"; break;
case EDEADLK: errVal = "EDEADLK"; break;
default: errVal = "unknown.."; break;
}
printf("Error taking lock in thread %lu: %s (%s)\n", pthread_self(), errVal , strerror(retVal));
}
return retVal == 0; //indicate success/failure
}
void UnlockMutex() {
pthread_mutex_unlock(&lock);
}
void TestLockNative() {
uint64_t thread_id = pthread_self();
printf("Trying to take lock in thread %lu.\n", thread_id);
int ret = LockMutex();
printf("Got lock in thread %lu. sucess=%d\n", thread_id, ret);
wut();
printf("Giving up lock now from thread %lu.\n", thread_id);
UnlockMutex();
}
void* test_thread(void* arg) {
//TestLock();
TestLockNative();
return NULL;
}
int main() {
InitMutex();
//create two threads which will try to access the protected function at once
pthread_t t1, t2;
pthread_create(&t1, NULL, &test_thread, NULL);
pthread_create(&t2, NULL, &test_thread, NULL);
//wait for threads to end
pthread_join(t1, NULL);
pthread_join(t2, NULL);
return 0;
}
The output of the program is e.g.:
Trying to take lock in thread 139845914396416.
Nanoseconds: 0, seconds 6000
pthread_mutex_timedlock(): 0
Got lock in thread 139845914396416. sucess=1
Trying to take lock in thread 139845906003712.
Nanoseconds: 0, seconds 6000
pthread_mutex_timedlock(): 110
Error taking lock in thread 139845906003712: ETIMEDOUT (Connection timed out) [<-- this occurs immediately, not after 60 seconds]
Got lock in thread 139845906003712. sucess=0
Giving up lock now from thread 139845906003712.
Compilation with gcc -o test test.c -lpthread
should work.
So, does anyone know what's going on here and why pthread_mutex_timedlock()
ignores my timeout value? It does not behave the way it is documented at all.
I'm using a Ubuntu 16.04.2 LTS system, compiling with gcc.
The protected state of the mutex cannot be recovered. The mutex is a robust mutex, and the process of the thread that owns the mutex terminated while holding the mutex lock. This function does not return the EINTR error code.
APPLICATION USAGE. The pthread_mutex_timedlock() function is part of the Threads and Timeouts options and need not be provided on all implementations.
The manual page for pthread_mutex_timedlock
says:
The timeout shall expire when the absolute time specified by abstime passes, as measured by the clock on which timeouts are based
Therefore, use real time to specify your timeout value:
int LockMutex() {
struct timespec timeoutTime;
clock_gettime(CLOCK_REALTIME, &timeoutTime);
timeoutTime.tv_sec += 60;
int retVal = pthread_mutex_timedlock(&lock, &timeoutTime);
....
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With