2010-11-24 61 views
1

我想知道是否可以設置從線程池獲得的線程的處理器關係。更具體地說,線程是通過使用TimerQueue API來獲得的,我使用它來實現定期任務。集合線程的SetThreadAffinityMask

作爲旁註:我發現TimerQueues是實現週期性任務的最簡單方法,但由於這些通常是長時間執行的任務,因此使用專用線程可能更適合此目的?此外,可以預料的是,需要使用諸如semapores和互斥體的同步初始化來同步各種週期性任務。這些池線是否適合這些?

謝謝!編輯1:正如獅子座指出,上述問題實際上是兩個只有鬆散相關的問題。第一個與池線程的處理器親和性有關。第二個問題涉及到從TimerQueue API獲得的池化線程是否像手動創建的線程一樣工作,就同步對象而言。我將把這個第二個問題作爲一個單獨的主題。

回答

2

如果你這樣做,確保你每次釋放一個線程回到池時都返回它們。由於您不擁有這些線程,因此使用它們的其他代碼可能會有其他要求/假設。

你確定你確實需要這樣做嗎?需要設置處理器親和性非常非常罕見。 (我認爲我從來沒有必要在我寫的任何東西中做到這一點)。

線程親和性可能意味着兩件完全不同的事情。(感謝bk1e到我原來的答覆的評論指出這一點我沒有意識到自己。)

  1. 我會打電話處理器親和力:如果一個線程需要在一個始終如一的運行同一處理器。這是SetThreadAffinityMask處理的內容,代碼關心它非常罕見。 (通常這是由於高性能代碼中的CPU緩存等非常低級的問題,通常操作系統將盡最大努力將線程保留在同一CPU上,並且通常會使其無法正常工作)

  2. 什麼我會打電話線程親和力:其中對象使用線程本地存儲(或其他一些與它們訪問的線程綁定的狀態),並且如果一系列操作未在同一線程上完成,將會出錯。

從您的問題,它聽起來像你可能會混淆#1和#2。線程本身不會改變而您的回調正在運行。當一個線程正在運行時,它可能會在CPU之間跳轉,但這是正常的,不是你必須擔心的事情(除非特殊情況)。

互斥量,信號量等不關心線程是否在CPU之間跳轉。

如果您的回調由線程池多次執行,則(取決於池的使用方式)通常不能保證每次都使用相同的線程。即您的回調可能會在線程之間跳轉,但不會在正在運行時跳轉;它只能在每次再次運行時更改線程。

某些同步對象關心您的回調代碼是否在一個線程上運行,然後仍然認爲它持有對這些對象的鎖定,再次在另一個線程上運行。 (第一個線程仍然保持鎖定,而不是第二個線程,儘管它取決於你使用的是哪一種同步對象。有些並不在意。)但這不是#1,那是#2,而不是你使用SetThreadAffinityMask來處理的東西。

作爲一個例子,Mutexes(CreateMutex)屬於一個線程。如果你在線程A上獲得一個互斥體,那麼任何其他嘗試獲取該互斥體的線程都會阻塞,直到你釋放線程A上的互斥體爲止(這也是一個線程釋放它不擁有的互斥體的錯誤)。你的回調獲得了一個互斥體,然後退出,然後在另一個線程上再次運行,並從那裏釋放互斥體,這將是錯誤的。

另一方面,事件(CreateEvent)並不關心哪些線程創建,發信號或銷燬它。你可以在一個線程上發出一個事件的信號,然後在另一個線程上重置它,這很好(實際上是正常的)。

在你的回調的兩次單獨運行之間保持一個同步對象(這會引起死鎖,儘管當然有你可以合理地想要/做這樣的事情的情況)也很罕見。但是,如果您創建了(例如)一個公寓線程的COM對象,那麼這將是您只想從一個特定線程訪問的內容。

+0

Microsoft的文檔還使用「線程關聯」來引用特定線程的處理器關聯性:http://msdn.microsoft.com/en-us/library/ms684251%28VS.85%29.aspx – bk1e 2010-11-24 15:06:47

0

你不應該。您只應該使用該線程來處理當前正在運行的處理器上的工作。除了明顯的低效之外,線程池可能會在您完成後立即銷燬每個線程,併爲您的下一個任務創建一個新線程。親和力掩模不會在實踐中很快消失,但如果它們隨機消失,則更難調試。