我目前正在用 C 撰寫一個程式,該程式使用執行緒模擬餐廳中的服務員和顧客。該程式運行 40 個客戶執行緒和 3 個服務員執行緒,具有如下功能:
void *customer(void * vargp){
//depending on assigned table, call waiter 1-3 using semaphore
sem_post(&callWaiter);
//wait for waiter to respond
sem_wait(&waiterResponse);
//leave table and finish thread
}
void *waiter(void *vargp){
//this is what I'm trying to fix
while(there are still customers){ //this check has been a number of different attempts
sem_wait(&callWaiter);
sem_post(&waiterResponse);
}
}
我試圖找到解決方案的問題是服務員會看到客戶仍然處于活動狀態(通過我嘗試過的幾種不同技術),然后阻塞等待信號量,然后客戶將完成并且不會再有顧客。有沒有人知道服務員執行緒如何檢查正在運行的客戶,而無需在最后一個客戶完成之前進行檢查?
uj5u.com熱心網友回復:
您正在尋找的是條件變數。它們在 pthreads 中,現在是 C 11 執行緒庫的一部分。它們是專門為解決您遇到的問題而構建的,因為您遇到的問題通常無法使用互斥鎖和海藻來解決。
但是,您需要的特定版本可能是可以解決的。我不知道您的特定作業問題是什么,但它可能與理發師睡覺的問題非常相似,它有幾個已知的解決方案,至少其中一個可以在上面的維基百科鏈接中找到。
uj5u.com熱心網友回復:
對于信號量,一種直接的方法是sem_getvalue()在初始化為客戶數量的信號量上使用。
int num_customers(bool = false){
int v;
sem_getvalue(&customers, &v);
return v;
}
當客戶離開時,每個人都sem_wait()在該信號量上執行。當sem_getvalue()回傳 0 時,表示所有客戶都已離開。
一個技巧是讓最后一位顧客叫醒他們的服務員,讓他們知道他們已經離開了。
//leave table and finish thread
sem_wait(&customers);
if (num_customers() == 0) sem_post(&callWaiter);
服務員在接待顧客之前會先檢查是否有顧客。
while(num_customers(true) > 0){
//wait for work
sem_wait(&callWaiter);
if (num_customers(true) == 0) break;
//work
sem_post(&waiterResponse);
}
最后一個顧客喚醒服務員的伎倆有一個無害的競賽,多個顧客可能每個人都認為他們是最后一個,因此服務員會收到多個帖子,每個帖子都表明沒有更多顧客。那些額外的帖子是無害的,因為無論如何服務員都會離開。但是,可以使用另一個初始化為 1 的信號量來避免這種競爭,用于讓第一個檢測到沒有更多客戶的客戶成為喚醒服務員的人。
int num_customers(bool is_waiter = false){
int v;
sem_getvalue(&customers, &v);
if (is_waiter) return v;
if (v == 0) {
if (sem_trywait(&last_customer) == -1) {
assert(errno == EAGAIN);
return 1;
}
}
return v;
}
uj5u.com熱心網友回復:
對于簡單狀態,可以使用原子變數:
// waiter
myId= waiter id
while(work)
{
work=false;
for(int n=0;n<40;n )
while (customerWaiterMatrix[n][myId].load()>0) // one of 120 atomic variables
{
work=true;
std::lock_guard<std::mutex>(mutexOfThatCustomerThisWaiter);
// thread safe customer logic
}
}
可以像這樣添加的地方:
// customer
myId = customer id
customerWaiterMatrix[myId][selectedWaiterId].fetch_add(1);
same lock of current customer & waiter with lock guard
Do safe logic
customerWaiterMatrix[myId][selectedWaiterId].fetch_add(-1);
鎖爭用減少,什么之后發生什么沒有歧義。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/336858.html
