2009-11-19 44 views
0

我有一個C#應用程序,需要在不中斷數據流的情況下將數據輸入流熱切換到新的處理程序類。如何強制多個命令在相同的線程時間片中執行?

要做到這一點,我必須執行在單個線程中的多個步驟而沒有任何其他線程(最所有數據recieving螺紋的)以在它們之間運行由於CPU切換。

這是一個簡化版本的情況,但它應該說明問題。

void SwapInputHandler(Foo oldHandler, Foo newHandler) 
{ 
    UnhookProtocol(oldHandler); 
    HookProtocol(newHandler); 
} 

這兩行(脫鉤和鉤)必須在相同的CPU執行切片,以防止任何從分組的情況下,獲得通過另一個線程在它們之間執行英寸

我怎樣才能確保這兩個命令運行squentially使用C#線程方法?

編輯
似乎有一些混亂,所以我會盡量更具體。我並不是說同時執行,就是在同一個cpu時間片內執行,以便在這兩個完成之前不執行任何線程。一個鎖不是我正在尋找的,因爲這隻會阻止這個代碼在兩個命令運行之前被再次執行。在完成這些命令之前,我需要阻止任何線程運行。另外,我再次說這是我的問題的簡化版本,所以不要試圖解決我的例子,請回答這個問題。

+1

您不應該關心託管代碼中的處理器調度問題。有可能有更好的方法來做你想做的事。你能提供更多的細節來說明你想達到的目標嗎? – Anton 2009-11-19 18:31:24

+0

您不希望它們同時運行 - 您希望它們順序運行而不會中斷。同時意味着它們都在同一時間運行。 – Aaron 2009-11-19 18:33:13

+0

好的 - 你的問題起初是誤導性的。你爲什麼不鎖定那些你不希望超過一個線程訪問的資源? – RichardOD 2009-11-19 18:45:08

回答

4

表演在一個時間片的操作不會在所有幫助 - 操作可能只是在執行並行另一核心或處理器同時執行交換訪問流。您將不得不使用鎖定來阻止每個人在處於不一致狀態時訪問數據流。

1

您的數據接收線程需要鎖定訪問處理程序指針,並且需要鎖定更改處理程序指針。

或者,如果您的處理程序是單個變量,則可以使用Interlocked.Exchange()以原子方式交換該值。

+0

這將無法正常工作,圍繞訪問處理程序引用的鎖定立即返回,您需要線程之間的共享鎖定,鎖定所有邏輯操作與處理程序應該是原子級的(IE讀取,然後寫入) – 2009-11-20 12:03:34

+0

@Pop是明智的建議,我們無法確定,因爲沒有給出實施細節。正確使用Interlocked.Exchange可以達到預期的效果。 – 2009-11-20 13:47:07

0

爲什麼不從另一個方向走,並讓有問題的線程處理交換。據推測,當有數據需要處理時就會醒來,並將其傳遞給當前的Foo。你可以發佈一個通知給那個線程,它需要在下一次喚醒時交換新的處理程序嗎?我會想,這會少得多。

+0

這個簡單的例子並不是指出整個問題,我只是尋找一個非常具體的答案來實現我的解決方案的一部分。由於應用的其他部分是結構化的,因此我無法使用您的建議。 – CodeFusionMobile 2009-11-19 18:46:35

0

好的 - 回答你的具體問題。

您可以通過在過程中的所有線程枚舉並呼籲每一個(除了活動之一)Thread.Suspend(),進行更改,然後調用Thread.Resume()。

+1

如果另一個線程試圖同時做同樣的事情會怎麼樣?任何可怕的事情都會出錯嗎?是否有任何線程結束暫停的情況? – 2009-11-19 22:11:16

+0

是的 - 如果兩個線程正在這樣做,他們可以相互殺死。我最初的推薦是使用鎖,但顯然OP更清楚... – Aaron 2009-11-19 23:20:54

+0

@Aaron如果我知道得更好,我不會問... – CodeFusionMobile 2009-11-24 16:24:02

0

假設你的處理程序是線程安全的,我的建議是寫在你處理一個公共的包裝,做了所有需要使用專用鎖,所以你可以放心地更改幕後的處理程序鎖定。

如果你這樣做,你也可以使用一個ReaderWriterLockSlim,用於訪問包裹的處理程序,它允許併發讀取訪問。

,或者你可以構建您的包裝類和處理程序clases以這樣一種方式,沒有鎖定是必需的,處理程序沼澤可以使用一個簡單的互鎖寫或者比較交換來完成。

這裏和示例:

public interface IHandler 
{ 
    void Foo(); 
    void Bar(); 
} 

public class ThreadSafeHandler : IHandler 
{ 

    ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(); 
    IHandler wrappedHandler; 

    public ThreadSafeHandler(IHandler handler) 
    { 
     wrappedHandler = handler; 
    } 

    public void Foo() 
    { 
     try 
     { 
      rwLock.EnterReadLock(); 
      wrappedHandler.Foo(); 
     } 
     finally 
     { 
      rwLock.ExitReadLock(); 
     } 
    } 

    public void Bar() 
    { 
     try 
     { 
      rwLock.EnterReadLock(); 
      wrappedHandler.Foo(); 
     } 
     finally 
     { 
      rwLock.ExitReadLock(); 
     } 
    } 

    public void SwapHandler(IHandler newHandler) 
    { 
     try 
     { 
      rwLock.EnterWriteLock(); 
      UnhookProtocol(wrappedHandler); 
      HookProtocol(newHandler); 
     } 
     finally 
     { 
      rwLock.ExitWriteLock(); 
     } 
    } 
} 

注意到,這一點,如果原子操作都需要在處理程序的方法仍然不是線程安全的,那麼你就需要使用胎面之間高階鎖定或添加方法你包裝類支持線程安全的原子操作(類似於BeginTreadSafeBlock()),它由EndTreadSafeBlock()實現,該操作鎖定包裝處理程序,以便爲一系列操作寫入數據。

0

你不能也不合邏輯。你可以做的最好的是避免任何其他線程中斷這兩個交流之間的狀態tions(如前所述)。

這是爲什麼你不能:

想象有如此告訴操作系統,而你是塊上從來都不是線程切換的塊。這在技術上是可能的,但會導致到處都是飢餓。

你可能是你的線程是唯一被使用的線程,但這是一個不明智的假設。有垃圾收集器,有與線程池線程一起工作的異步操作,像COM對象這樣的外部引用可以跨越它自己的線程(在你的內存空間中),這樣任何人都可以在你進行操作時取得進展。

想象一下,您在HookOperation方法中進行了非常長的操作。它涉及很多非泄漏操作,但由於垃圾收集器無法接管來釋放資源,因此最終沒有任何內存。或者想象一下,你調用一個使用多線程處理請求的COM對象...但它不能啓動新線程(它可以啓動它們但是它們永遠不會運行),然後加入它們等待它們在未來之前完成回來...因此你加入自己,永遠不會回來!!

0

正如其他海報已經說過的那樣,您無法在用戶模式代碼中執行系統範圍的關鍵部分。但是,您並不需要它來實現熱插拔。

這裏是如何。

使用與熱插拔Foo對象相同的接口實現代理。代理應調用HookProtocol並且永不解除掛鉤(直到您的應用停止)。它應包含對當前Foo處理程序的引用,您可以在需要時使用新實例替換它。代理應將它從掛鉤函數接收到的數據導向當前處理程序。此外,它還應該提供一個原子替換當前Foo處理程序實例的方法(有多種方法可以實現它,從簡單的互斥鎖到無鎖)。

相關問題