2011-12-04 115 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); 
} 

使用另一種方法(未示出),然後我可以實現產率(),只有當有或者沒有線程等待鎖返回,或後至少有一個其他線程有機會運行。

這個實現大多數情況下工作正常,但是如果我用大約50個線程試圖以隨機間隔獲取和釋放鎖來進行壓力測試,每隔一段時間acquire()將返回EPROTO,表示某人稱爲pthread_cond_signal而不設置第一個lock_taken = FALSE

這是爲什麼?看起來好像CPU有時看不到lock_taken的新值,這就是爲什麼我已經使變量變得不穩定。但它仍然發生......

回答

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

這應該是while(lock_taken),不if。有幾個原因可能會從pthread_cond_wait中醒來,但在您計劃的時間內找到另一個線程佔用的鎖。一個是如果有虛假的喚醒。另一種情況是,如果另一個線程在我們阻塞之後輸入acquire,則發現該鎖未被佔用,並且在該線程再次獲得互斥之前將其自己佔用。

的典型方法是:

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

破除一切volatile S的,他們傷害的性能,而不是必要的。由於互斥體足夠同步,所以沒有其他必要。 (而且,對於看着你的代碼的任何人來說,他們表示你不懂線程同步,並試圖「灑入」它,直到它碰巧正常工作。)

+0

謝謝!在等待的線程有機會抓住釋放的鎖之前,我看到另一個線程進入'acquire'的時刻。但是,您提到的「虛假喚醒」是否還有其他原因? * pthread_cond_signal(3)*表示它正在喚醒一個線程。在我的辯護中:我不相信'volatile'是必需的,但是我撒了他們以防萬一我錯了:-)。 – Nikratio

+0

與'acquire'有同樣的問題可能會出現在* pthreads庫本身內部,無法控制。由於pthreads庫不能訪問謂詞,因此它不能在內部使用'while'循環。所以它有同樣的問題,但它無法解決它。 –

+0

因此,* pthread_cond_signal(3)*顯然是錯誤的?這裏的描述似乎沒有考慮到你描述的可能性(但我還發現了其他幾個問題和關於虛假喚醒的維基百科文章,所以我傾向於相信你)。 – Nikratio