Je souhaite protéger une fonction contre un accès multithread. Pour ce faire, j'utilise un mutex pthread_mutex_t
. J'essaie de le verrouiller au début d'une fonction, puis d'exécuter la fonction, puis de la relâcher. Si le mutex est utilisé, il doit attendre au maximum 60 secondes pour qu'il soit disponible. Si après cela, il n'est toujours pas disponible, la fonction devrait échouer.pthread_mutex_timedlock() se ferme prématurément sans attendre le délai
Le problème que j'ai est que pthread_mutex_timedlock
semble ignorer complètement la valeur de délai que je lui donne. Bien que je spécifie un délai de 60 secondes, si le verrou est pris, la fonction renvoie immédiatement avec le code d'erreur ETIMEDOUT
- sans attendre réellement.
Voici un exemple minimal qui reproduit le problème. Dans ce cas, peu importe que j'utilise des mutex récursifs ou non récursifs, puisque je n'essaie pas de les verrouiller plusieurs fois à partir du même 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;
}
La sortie du programme est .: par exemple
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 avec gcc -o test test.c -lpthread
devrait fonctionner. Donc, est-ce que quelqu'un sait ce qui se passe ici et pourquoi pthread_mutex_timedlock()
ignore ma valeur de délai d'attente? Il ne se comporte pas du tout the way it is documented. J'utilise un système Ubuntu 16.04.2 LTS, compilant avec gcc.
Un mot simple, ou plutôt, mon incapacité à lire le paramètre r valeur ou cette ligne dans la documentation a provoqué ce problème. Merci beaucoup. –
Je suis heureux d'avoir pu aider :) – LWimsey