26

スレッドプールの新しいスレッドに 2 つのパラメーターを渡すのは複雑な場合がありますが、ラムダ式と匿名メソッドを使用すれば、次のようにできるようです。

public class TestClass
{
    public void DoWork(string s1, string s2)
    {
        Console.WriteLine(s1);
        Console.WriteLine(s2);
    }
}

try
{
    TestClass test = new TestClass();
    string s1 = "Hello";
    string s2 = "World";
    ThreadPool.QueueUserWorkItem(
        o => test.DoWork(s1, s2)
        );
}
catch (Exception ex)
{
    //exception logic
}

ここで、この例を単純化しましたが、次の点が重要です。

  • 渡される文字列オブジェクトは不変であるため、スレッドセーフです
  • s1 変数と s2 変数は、try ブロックのスコープ内で宣言されます。このブロックは、作業をスレッド プールのキューに入れたらすぐに終了します。そのため、s1 変数と s2 変数はその後変更されることはありません。

これに何か問題がありますか?

別の方法は、test、s1、s2 の 3 つのメンバーを持つ不変型を実装する新しいクラスを作成することです。これは、現時点では何のメリットもない余分な作業のように思えます。

4

5 に答える 5

16

これには何も問題はありません。コンパイラは、基本的に、代替として説明したことを自動的に実行しています。キャプチャされた変数 (test、s1、および s2) を保持するクラスを作成し、匿名クラスのメソッドに変換されるラムダにデリゲート インスタンスを渡します。言い換えれば、代替案を先に進めた場合、コンパイラが生成したものと非常によく似たものになるでしょう。

于 2009-04-10T16:24:39.860 に答える
4

この特定の例については、何も問題はありません。他のスレッドに渡した状態は完全に含まれており、関連するタイプにはスレッド アフィニティの問題はありません。

于 2009-04-10T16:22:42.250 に答える
2

あなたが見ているものはクロージャーと呼ばれます。チャックジが述べているように、コンパイラはコンパイル時に、クロージャの外部でアクセスされるメンバーに対応するクラスを生成しています。

心配する必要があるのは、ref または out パラメータがあるかどうかだけです。文字列は不変ですが、それら (または任意の変数) への参照は NOT です。

于 2009-04-10T16:27:27.857 に答える
2

このパターンの潜在的な問題の 1 つは、次のように、より一般的ではあるが安全性の低いものに拡張したくなることです (スクラッチ コード - 動作するとは思わないでください)。

public static void QueueTwoParameterWorkItem<T1, T2>(T1 value1, T2 value2, workDelegate<T1,T2> work)
{
    try
    {
        T1 param1 = value1;
        T2 param2 = value2;
        ThreadPool.QueueUserWorkItem(
            (o) =>
            {
                work(param1, param2);
            });
    }
    catch (Exception ex)
    {
        //exception logic
    }
}
于 2009-04-10T16:28:52.703 に答える
2

それはそれを行う素晴らしい方法です。ラムダを使用することの欠点はありません。シンプルでクリーンです。

于 2009-04-10T16:21:43.377 に答える