2013-10-28 58 views
1

我想不出合乎邏輯的解決方案。 有兩個流 - 主要和孩子。 他們必須依次顯示類似這樣的消息:生產者消費者只有互斥體

家長

兒童

家長

... 等等各做10次。

您只能使用pthread互斥鎖並且不要使用閒置循環。 僅在初始化階段允許空閒循環。 誰 - 誰知道一個很好的解決方案?

回答

3

我想我明白了......大提示是「只有在初始化階段才能完成空閒」。

首先,對互斥的限制是,你必須在你鎖定了同一個線程解鎖。因此,在一個線程每個unlock()必須以lock()配對,我們必須讓他們同等數量(或否則我們會得到一個死鎖)。

這意味着我們可以防止多次打印線程的唯一方法是確保每個線程始終擁有至少一個MUTEX。如果線程B在任何時候釋放了所有的互斥鎖,然後CPU切換到線程A,它可能會無限期地運行。

我們不能用2個互斥沒有僵局做到這一點,但我們可以用3

父線程做到這一點:

bool initDone = false; 
    lock(m1); 
    lock(m2); 
    spawnChild(); 
    while (!initDone) 
     sleep(); 
    while (true) { 
     print("Parent"); 
     unlock(m1); 
     lock(m3); 
     unlock(m2); 
     lock(m1); 
     unlock(m3); 
     lock(m2); 
    } 

子線程:

lock(m3); 
    initDone = true; 
    while (true) { 
     lock(m1); 
     unlock(m3); 
     lock(m2); 
     print("Child"); 
     unlock(m1); 
     lock(m3); 
     unlock(m2); 
    } 

我們開始與父母擁有鎖1和2,並擁有孩子3.然後他們輪流釋放和獲取鎖:父母給孩子鎖1,孩子給父母鎖3,父母給孩子鎖2,孩子給鎖1對父母,父母給孩子鎖3,孩子給父母鎖2,重複。

一個有趣的問題;我敢打賭,你現在看到了條件變量的吸引力,因爲它們使這一點變得微不足道。

+0

您不能使用sleep或shed_yield函數,只能使用互斥鎖。 – Dima00782

+0

@ Dima00782更新了我的答案,以便它只在初始化期間閒置;我現在非常自信,這是最好的解決方案。 –

+0

大聲笑愛它 –

0

您可能需要更具體的要求。如果切換輸出是唯一的實際需求,那麼這樣的事情應該工作(有點假的codeY):

const char *strings[2] = { "Parent", "Child" }; 
pthread_mutex_t m; // needs to be properly initialized, of course 
int which = 0; 

thread_func() 
{ while (1) 
    { lock(&m); 
    printf("%s\n", strings[which]) 
    which = !which; 
    unlock(&m); 
    } 
} 

,只要你想你可以產卵多線程,輸出將繼續交替。但是,線程不一定每次交錯一次迭代。試圖獲得適當的單迭代交錯只有一個互斥量和沒有屈服函數(pthreads沒有指定)是有點困難...

+0

對不起,我把它準確。應該有兩個線程。一個打印父母,第二個孩子。 – Dima00782

0

你需要的是2線程(父母和孩子)允許每個其他要執行。

這是僞代碼,你可以自由使用任何你想要的鎖定原語。

//global variables and initializations 
parent_lock = UNLOCKED; //This allows your first print to be from parent 
child_lock = LOCKED; 

parent_counter = 0; //to count the number of prints 
child_counter = 0; 

//Parent should do this     |  //Child should do this 
while(1)         |while(1) 
{          | 
spin: if(parent_lock == LOCKED)   |spin: if(child_lock == LOCKED) 
     {         |  { 
     //spin till child unlocks you |  //spin till parent unlocks you 
      goto spin;      |   goto spin; 
     }         |  } 
     else        |  else 
     {         |  { 
      print("PARENT");    |   print("CHILD"); 
      parent_counter++;    |   child_counter++; 
      //lock yourself allow the other|   //lock yourself allow the other 
      parent_lock = LOCKED;   |   child_lock = LOCKED; 
      child_lock = UNLOCKED;   |   parent_lock = UNLOCKED; 
      if (parent_counter == 10)  |   if (child_counter == 10) 
      {        |   { 
       break;//printed 10 times |    break;  
      }        |   } 
     }         |  } 
}          |} 

//PARENT has printed 10times wait for |//CHILD has printed 10times wait for 
//child         |// parent 

PS:*我認爲你可以自由旋轉的鎖,這是我做了什麼,如果這不是你需要修改上述算法做睡眠和喚醒,而不是旋轉的情況下, 。
*您可以選擇pthread鎖原語來初始化parent_lock和child_lock。
*爲使程序正確無誤,我們需要假定賦值語句是原子Ex:child_lock = LOCKED語句是原子的。

極其重要:見家長的順序:

parent_lock = LOCKED; 
child_lock = UNLOCKED; 

和計數器部分的子線程。 如果你交換這兩行,那麼你可能DEADLOCK !!!!,因爲由父母和孩子混合執行的序列(由於OS調度程序)。

+0

這是我的第一個想法,但使用pthread互斥鎖,您不會(可靠地)從子項解鎖父鎖,反之亦然:「如果調用線程當前不保存互斥鎖(通過先前調用pthread_mutex_lock ()或pthread_mutex_trylock()),解鎖請求將失敗並顯示EPERM結果。「 –