代码之家  ›  专栏  ›  技术社区  ›  Maximilian Gerhardt

pthread\u mutex\u timedlock()在不等待超时的情况下过早退出

  •  6
  • Maximilian Gerhardt  · 技术社区  · 7 年前

    pthread_mutex_t 互斥体。我尝试在函数的开头锁定它,然后执行该函数,然后再次释放它。如果互斥锁正在使用,则应等待最长60秒,以使其可用。如果在此之后仍然不可用,则该功能应失败。

    我的问题是 pthread_mutex_timedlock 似乎完全忽略了我给出的超时值。虽然我指定了60秒的超时时间,但如果锁定,该函数会立即返回错误代码 ETIMEDOUT --没有真正等待。

    这是一个再现问题的最小示例。在这种情况下,我使用递归还是非递归互斥锁并不重要,因为我并没有试图从同一个线程多次锁定它们。

    #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;
    }
    

    程序的输出例如:

    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.
    

    使用编译 gcc -o test test.c -lpthread 应该有效。

    那么,有人知道这里发生了什么以及为什么吗 pthread_mutex_timedlock() 忽略我的超时值?它不正常 the way it is documented 完全

    1 回复  |  直到 7 年前
        1
  •  12
  •   LWimsey    7 年前

    的手册页 pthread_mutex_timedlock 说:

    根据超时所依据的时钟

    因此,请使用real time指定超时值:

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