マルチスレッドアクセスから関数を保護したい。その目的のために私はpthread_mutex_t
ミューテックスを使用しています。私は関数の始めにそれをロックしようとし、関数を実行してから再び解放します。ミューテックスが使用されている場合、ミューテックスが使用可能になるまで最大60秒間待機する必要があります。それでもまだ使用できない場合、関数は失敗するはずです。タイムアウトを待つことなくpthread_mutex_timedlock()が早期に終了する
私が抱えている問題は、pthread_mutex_timedlock
がタイムアウト値を完全に無視しているようです。私は60秒のタイムアウトを指定しますが、ロックが取られれば、関数は実際には待たずにエラーコードETIMEDOUT
で直ちに戻ります。
問題を再現するための最小限の例を示します。この場合、同じスレッドから複数回ロックしようとしていないので、再帰的または非再帰的なmutexを使用しているかどうかは関係ありません。
#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;
}
プログラムの出力は、例えば:gcc -o test test.c -lpthread
と
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.
コンパイルが動作するはずです。
だから誰でもここで何が起こっているのか、なぜpthread_mutex_timedlock()
は私のタイムアウト値を無視するのですか? the way it is documentedはまったく動作しません。
私はgccでコンパイルしたUbuntu 16.04.2 LTSシステムを使用しています。
単純な言葉ではなく、むしろパラメタを読むことができませんr値またはドキュメントのこの行でこの問題が発生しました。どうもありがとうございました。 –
私は助けることができる嬉しい:) – LWimsey