c - pthread_mutex_timedlock() 过早退出而不等待超时

标签 c linux multithreading pthreads mutex

我想保护一个函数免受多线程访问。为此,我使用了 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完全没有。

我使用的是 Ubuntu 16.04.2 LTS 系统,使用 gcc 编译。

最佳答案

pthread_mutex_timedlock 的手册页说:

The timeout shall expire when the absolute time specified by abstime passes, as measured by the clock on which timeouts are based

因此,使用实时来指定您的超时值:

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

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

关于c - pthread_mutex_timedlock() 过早退出而不等待超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46365448/

相关文章:

regex - 使用 'awk' 从日志文件中提取特定的 XML 模式

java - 以给定的执行时间启动线程

Python 线程/子进程;当子进程仍在运行时,线程对象无效

c - 我的字符、单词、行数计数程序有什么问题?

c - xxxxx_()、LAPACK_xxxxx() 和 LAPACKE_xxxxx() 函数之间的区别

c - 长文件路径的 stat 替代方案

小端大端的混淆

linux - ps -ef 在 Asterisk 重新启动期间崩溃

linux - 使用 AWK 组合(合并)多行

java - Java 中 System.out.println() 的 volatile