我想保护一个函数免受多线程访问。为此,我使用了一个pthread_mutex_t互斥锁。我尝试在函数开头锁定它,然后执行函数,然后再释放它。如果互斥锁正在使用中,它应该等待最多60秒钟,直到可用为止。如果在那之后仍然无法获得,函数就应该失败。
我遇到的问题是pthread_mutex_timedlock似乎完全忽略了我给它的超时值。虽然我指定了60秒的超时时间,但如果锁已被占用,则函数立即返回错误代码ETIMEDOUT - 而不是实际等待。
以下是一个最小化的示例,可以重现该问题。在这种情况下,无论我使用递归或非递归互斥锁都没有关系,因为我不会从同一线程多次尝试锁定它们。
程序的输出示例如下:
我遇到的问题是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()
忽略了我的超时值吗? 它根本不按照文档中所述的方式行事。
我正在使用Ubuntu 16.04.2 LTS系统,并使用gcc编译。