2017-09-22 4 views
2

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.

Répondre

5

La page de manuel pour pthread_mutex_timedlock dit:

Le délai expire lorsque le temps absolu spécifié par abstime passe, tel que mesuré par l'horloge sur laquelle les délais d'attente sont basées

Par conséquent, l'utilisation temps réel pour spécifier votre valeur de délai d'expiration:

int LockMutex() { 
    struct timespec timeoutTime; 
    clock_gettime(CLOCK_REALTIME, &timeoutTime); 
    timeoutTime.tv_sec += 60; 

    int retVal = pthread_mutex_timedlock(&lock, &timeoutTime); 
    .... 
+0

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. –

+0

Je suis heureux d'avoir pu aider :) – LWimsey