2011-12-04 32 views
2

あるスレッドから別のスレッドへコンテキストを強制的に切り替えることができます。したがって、私は、次のロック手順を実装している:スレッドコンテキストスイッチを強制的に実行する

#define TRUE (1==1) 
#define FALSE (0==1) 

#include <pthread.h> 

int acquire(void); 
int release(void); 
int c_yield(int count); 

// Who was the last to acquire the lock 
static volatile pthread_t lock_owner; 

// Is the lock currently taken 
static volatile int lock_taken = FALSE; 

/* This variable indicates how many threads are currently waiting for 
* the lock. */ 
static volatile int lock_wanted = 0; 

/* Mutex for protecting access to lock_wanted, lock_owner and 
* lock_taken */ 
static pthread_mutex_t mutex; 

/* Condition even to notify when the lock becomes available */ 
static pthread_cond_t cond; 

void init_lock(void) { 
    pthread_cond_init(&cond, NULL); 
    pthread_mutex_init(&mutex, NULL); 
} 

int acquire(void) { 
    pthread_mutex_lock(&mutex); 
    if(lock_taken) { 
     lock_wanted++; 
     pthread_cond_wait(&cond, &mutex); 
     lock_wanted--; 
    } 
    if(lock_taken) { 
     pthread_mutex_unlock(&mutex); 
     return EPROTO; 
    } 
    lock_taken = TRUE; 
    lock_owner = pthread_self(); 
    return pthread_mutex_unlock(&mutex); 
} 

int release(void) { 
    pthread_mutex_lock(&mutex); 
    lock_taken = FALSE; 
    if(lock_wanted > 0) { 
     pthread_cond_signal(&cond); 
    } 
    return pthread_mutex_unlock(&mutex); 
} 

を別の方法を使用して(図示せず)、Iは、次いで、(歩留まりを実現することができる)だけロックを待っているスレッドのいずれかが存在しない場合返し、または、後こと少なくとも1つの他のスレッドが実行する機会がありました。

ほとんどの場合、この実装はうまく動作しますが、ランダムな間隔でロックを取得および解放しようとする〜50スレッドでストレステストを実行すると、acquire()はたびたびEPROTOを返します。最初に設定しないでpthread_cond_signalと呼ばれます。lock_taken = FALSE

なぜですか? CPUが時々新しい値lock_takenを見ないように思えます。そのため私はすでに変数をvolatileにしています。しかし、それはまだこれはwhile(lock_taken)、ないifでなければなりません...

答えて

7
if(lock_taken) { 
    lock_wanted++; 
    pthread_cond_wait(&cond, &mutex); 
    lock_wanted--; 
} 

が起こっています。 pthread_cond_waitから復帰する理由はいくつかありますが、スケジュールされるまでに別のスレッドがロックを取得していることがわかります。 1つは偽の起床がある場合です。もう1つは、別のスレッドがブロックした後にacquireに入った場合、ロックが取られていないことを検出し、このスレッドが再びmutexを取得する前にそれ自身を取ります。

標準的な方法は次のようになります。

lock_wanted++; 
while(lock_taken) pthread_cond_wait(&cond, &mutex); 
lock_wanted--; 

はすべてvolatile Sを取り除く、彼らはパフォーマンスに悪影響を与えるとは必要ありません。ミューテックスは十分な同期であるため、他に何も必要ありません。 (そして、あなたのコードを見ている他の人には、スレッド同期を理解しておらず、ただちに動作させるまで「それらを振りかざしてみた」というメッセージが表示されます)

+0

ありがとう!待っているスレッドが解放されたロックを取得する機会があった前に、別のスレッドが 'acquire'に入っている点がわかります。しかし、あなたが言及した「間違った起床」の理由は他にありますか? * pthread_cond_signal(3)*は、ちょうど1つのスレッドを目覚めさせていると言います。私の防衛の中では、「揮発性」が必要だとは思っていませんでしたが、私が間違っている場合にはそれらを振りかけることができました:-)。 – Nikratio

+0

pthreadsライブラリ自体で制御できない方法で 'acquire'と同じ問題が発生することがあります。 pthreadsライブラリは述語にアクセスできないため、内部的に 'while'ループを使用することはできません。だからあなたと同じ問題がありますが、それを修正する方法はありません。 –

+0

So * pthread_cond_signal(3)*は間違っていますか?その説明は、あなたが説明する可能性を考慮していないようです(しかし、私はまたいくつかの疑問や偽の起床に関するウィキペディアの記事を見つけました。 – Nikratio

関連する問題