2015-11-03 59 views
-1

考慮兩個線程同時運行。 A是閱讀,B是寫作。當A正在讀取時,在代碼中間,A的CPU時間結束,然後B線程繼續。強制線程不要讓CPU退回到零件完成

有沒有什麼辦法可以在A完成之前不放棄CPU,但B可以啓動還是繼續?

+2

是線程的讀數線程B寫入數據?這是[生產者/消費者問題](https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem)的例子嗎?還是你想簡單地阻塞一個線程,直到另一個線程完成或以其他方式發出信號? – Dai

+0

是的。我不想在A的中間給CPU回來。但也許B線程有一些東西要寫。您知道,如果在CPU時間結束的時候,檢索到的數據不完整。 –

+0

如果A和B共享資源,您仍然沒有說清楚。請張貼一些代碼來演示您遇到的問題。 – Dai

回答

1

你需要明白,你有幾乎沒有控制當CPU被給回和給誰它。操作系統這樣做。爲了控制這個,你需要成爲操作系統。你通常可以做的唯一的事情是:

  • 啓動一個線程
  • 設置線程的優先級,所以有些線程可能更容易得到的時間比別人
  • 把一個線程睡眠,immediatelly並要求操作系統在某些情況下喚醒它,也許有一些超時(等待時間限制)

作爲一種特殊情況,或者一個典型的用例,第二點通常也是具備速記:

  • 把一個線程睡眠,immediatelly的時間

規定量「休眠」我的意思是,這個線程暫停並不會得到任何CPU時間,即使所有的CPU都空閒,除非線程被某些條件喚醒。另外,在典型的情況下,沒有「線程A和線程B在它們之間切換CPU時間」,但是「有很多來自各種進程和操作系統本身的線程,以及你們兩個線程」。這意味着當你的線程A失去了CPU時,很可能現在不會是線程B獲得時間。來自其他地方的其他線程會得到它,並且在將來的某個時間點,也許你的線程A或者線程B會返回它。

這意味着你可以確定的東西很少。你可以肯定,你的線程是

  • 要麼死亡
  • 或睡眠
  • 或法律程序硬「轉發」,以確定爲了

如果你需要確保一些線程同步,你必須......不要同時啓動它們,或讓它們在精確的時刻睡覺並按照精確的順序將它們喚醒。


你的意見只是說:

你知道,如果在一個CPU時間完成,數據已被檢索的中間是不能完成

這意味着您需要確保線程B在線程A完成寫入之前不嘗試觸摸數據。但是,如果您仔細想想,如果線程B正在讀取以前的數據,則需要確保線程A不會開始寫入下一個數據。

這意味着同步。這意味着線程A和B必須等待等待如果其他線程正在觸摸數據。這意味着當另一個線程結束時,他們需要睡覺並醒來。

在C#中,最簡單的方法是使用lock(x)關鍵字。當一個線程輸入lock()部分時,它只有在它能夠獲得鎖定時纔會繼續。如果不是的話,它就會入睡。如果任何其他線程更快,並且之前獲得它,它就無法獲得鎖定。但是,線程在結束作業時會釋放鎖。那時候,其中一個睡眠線程被喚醒並給予鎖定。

lock(fooo) { // <- this line means 'acquire the lock or sleep' 

    iam.doing(myjob); 
    very.important(things); 
    thatshouldnt.be.interrupted(); 
    byother(threads); 

} // <- this line means 'release the lock' 

所以,當一個線程獲得通過lock(fooo){線,你不能肯定它不會被打斷。哦,當然會。 OS會將線程來回切換到其他進程,等等。但是您可以確定您的應用程序的其他線程將位於代碼塊內。如果他們試圖在你的線程獲得鎖定時進入內部,他們會立刻在第一條lock線中入睡。其中一個將在您的線程離開該代碼後稍後被喚醒。

還有一件事。 lock()關鍵字需要一個參數。那裏寫了foo。你需要通過那裏作爲鎖。它可以是任何對象,甚至普通的對象:

private object thelock = new object(); 

private void dosomething() 
{ 
    lock(thelock) 
    { 
     foobarize(thebaz); 
    } 
} 

但是你必須確保所有線程嘗試使用相同的鎖定實例。寫作就像

private void dosomething() 
{ 
    object thelock = new object(); 
    lock(thelock) 
    { 
     foobarize(thebaz); 
    } 
} 

的一個代碼,因爲每一個潛在的線程執行該行會盡量洛在他們自己的新的對象實例,並把它看作是「自由」(它是新的,剛剛創建,沒有人把它更早)廢話並立即進入受保護的代碼塊。


現在你寫了關於使用ConcurrentQueue。該類提供了針對併發的安全機制。您可以確定添加,讀取或刪除該隊列中的項目已經安全。這個集合使它安全。您無需添加同步即可安全地添加或移除項目。它是安全的。如果您觀察到任何不良影響,那麼很可能您已嘗試將一件物品放入該集合中,然後您修改了該項目即。併發收集不會阻止你。它只能確保添加/刪除/等是安全的。但對你做的項目是什麼沒有知識或控制:

總之,如果某個線程B試圖在線程A這從集合中讀取項目,然後是不是安全:

concurrentcoll.Add(item); 
item.x = 5; 
item.foobarize(); 

但這是安全的:

item.x = 5; 
item.foobarize(); 
concurrentcoll.Add(item); 
// and do not touch the Item anymore here.