2009-08-14 9 views
6

私はネイティブdllを頻繁に呼び出すマルチスレッドのC#Windowsアプリケーションを開発中です。これは時にはかなり長い時間がかかることがあるコールをブロックしています。特定の状況でManagedThreadIDとオペレーティングシステムThreadIDの関係

、私は私が使用しているネイティブAPIは、この目的のための機能を提供し、メインスレッドからいくつかのワーカースレッド上でこれらのブロッキング呼び出しをキャンセルしたい:のドキュメントが、

HRESULT CancelBlockingCall(DWORD ThreadID) 

CancelBlockingCall()は非常に明確ではない、私は、呼び出しでブロックされているOSレベルのスレッドのThreadIDを渡す必要があると思う。私がCancelBlockingCall()から取得しているリターンコードに基づいて、私はThread.ManagedThreadIDが私が必要としているものではないことに気付きました。

管理対象外のホストの管理とアンマネージスレッド間の関係を制御することができますので、マネージスレッドへの一定の関係を持っていないスレッドIDオペレーティングシステム:私はmsdn (see the Note)に次を発見しました。 具体的には、洗練されたホストは、CLR Hosting APIを使用して、同じオペレーティングシステムスレッドに対して多くの管理された スレッドをスケジュールするか、管理対象スレッドを異なるオペレーティングシステムスレッド の間で移動できます。

これは管理されたスレッドに対してCancelBlockingCall()を正しく呼び出す方法がないことを意味しますか?管理スレッドが現在実行されているOSレベルのスレッドのThreadIdを特定することは不可能ですか?あなたはPを試みることができる

答えて

4

を呼び出すと、これは私が適切に管理スレッドのCancelBlockingCall()を呼び出すための方法がないことを意味するのでしょうか?管理スレッドが現在実行されているOSレベルのスレッドのThreadIdを特定することは不可能ですか?

エイダン氏によると、GetCurrentThreadID APIを使用してOSスレッドIDを取得できます。

管理スレッド間でそれを追跡するためにあなたが後でそれを止めることができるように、あなたは、あなたがOSのスレッドIDを格納するクラスであなたのAPI呼び出しをラップすることができます:

public class APITask 
{ 
    private uint _osThreadId; 

    public void Run() 
    { 
     _osThreadId = GetCurrentThreadID(); 
     API.RunBlockingMethod(); 
    } 

    public void Cancel() 
    { 
     API.CancelBlockingCall(_osThreadId); 
    } 
} 
0

どうAbortable ThreadPoolを使用してはどうですか?

記事から。

代わりに、キューに入れられた作業項目のソートのクッキーを返すスレッドプールの実装を考えてみましょう。プールはまた、これらのクッキーの1つを取り、関連付けられた作業項目を取り消し、キューから取り除き、または実行中の作業項目を適切に中止するCancelメソッドを提供することができる。おそらく、このタスクのためのカスタム・スレッド・プールを実装することは最高のアイデアではありませんが、他の選択肢

13

他の人が述べたように、あなたは、ブロッキングネイティブ関数を呼び出すと、どこかにそのIDを登録する前GetCurrentThreadIdを呼び出す/ P試みることができるがありますこれは時の爆弾です。管理されたスレッドは、2つのp/invoke呼び出しの間で異なるOSレベルのスレッドに先取りされ、再スケジュールされます。私が示唆できる唯一の信頼できる方法は、最初にGetCurrentThreadId(それをout IntPtr管理コードに表示される場所に書き込む)とネイティブのブロック機能を呼び出す小さな管理されていないプロキシDLLを作成することです。 out IntPtrの代わりにマネージコードへのコールバックも機能します。スタック上に管理されていないフレームがある間は、CLRはスレッドを再スケジュールすることはほとんどありません。

編集:どうやらあなたは、このような問題を抱えている最初の人じゃない:Thread.BeginThreadAffinity()Thread.EndThreadAffinity():1は私が述べたtimebombを打開し、P/GetCurrentThreadId()を呼び出すことができSystem.Threading.Threadに2つの便利な方法があります。 CLRホストは、管理されたスレッドをこれらの呼び出し間で別のネイティブスレッドにスケジュール変更しません。ただし、これらのメソッドを呼び出すには、コードを高い信頼レベルで実行する必要があります。

+0

上記のアプローチのリスクを強調するために+1 – Odrade

+0

はい、良い点! –

+0

更新いただきありがとうございます。私があなたにもう一度あなたをアップウォートすることができたら、私はそうするでしょう。 – Odrade