パラメータ付きのThreadStart


261

C#でパラメーターを使用してスレッドを開始するにはどうすればよいですか?


この質問に対する回答は、ランタイムのバージョンによって大きく異なります。3.5の回答で問題ありませんか?
クイルブレーカー、2009

4
ワオ。私はあなたの古い質問のいくつかを編集してきましたが、それはフルタイムの仕事かもしれません。私は、あなたが長年にわたってどれだけ改善したかを忘れていました。:-)
John Saunders

このような簡単な質問をした場合、5つ以上の否定的なスコアが表示されます。質問と答えは私を助けましたが。
Mohammad Musavi

回答:


174

うん:

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);

14
これは同じです:ThreadStart processTaskThread = delegate {ProcessTasks(databox.DataboxID); }; 新しいThread(processTaskThread).Start();
JL。

43
myParamObjectおよびmyUrlとは何ですか?
dialex

3
この場合void MyParamObject(object myUrl){ //do stuff }、パラメータタイプが必要ですobject
Elshan 2014年

15
-1は、OPがParameterizedThreadStart質問テキストからわかりやすく使用方法を知っていることを前提としているため、おそらくそうではありません。
JYelton、2015

2
このエラーが発生しましたエラーCS0123 'UpdateDB'のオーバーロードはデリゲート 'ParameterizedThreadStart'に一致しません
Omid Farvid

482

スレッドコンストラクターの2つのオーバーロードの1つは、単一のパラメーターを開始メソッドに渡すことができるParameterizedThreadStartデリゲートを使用します。残念ながら、それは単一のパラメーターのみを許可し、それをオブジェクトとして渡すため、危険な方法で許可します。ラムダ式を使用して関連するパラメーターをキャプチャし、厳密に型指定された方法で渡す方がはるかに簡単です。

以下をお試しください

public Thread StartTheThread(SomeType param1, SomeOtherType param2) {
  var t = new Thread(() => RealStart(param1, param2));
  t.Start();
  return t;
}

private static void RealStart(SomeType param1, SomeOtherType param2) {
  ...
}

41
+1:現在選択されている答えは完全に正しいですが、JaredParによるこれがより良い答えです。これは、ほとんどの実際的なケースに最適なソリューションです。
ガラクトール09/10/10

2
このソリューションは、標準のParameterizedThreadStartよりもはるかに優れています
Piotr Owsiak 2010

5
とてもシンプルです。すべての呼び出しを "new Thread(()=> FooBar()).Start();でラップするだけ
Thomas Jespersen

12
すごい、これはVB.NETの人向けですDim thr As New Thread(Sub() DoStuff(settings))
dr。悪

3
@bavaza静的型チェックについて言及しただけ
JaredPar

141

ラムダ式を使用できます

private void MyMethod(string param1,int param2)
{
  //do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();

これはこれまでのところ私が見つけた最良の答えです、それは速くて簡単です。


6
シンプルなケースのIMOに最適なソリューション
2013

1
それは何ですか=>?構文に関する詳細情報はどこにありますか?
ニック

2
これはラムダ式であり、いくつかの情報はこれらのアドレスで見つけることができます:msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it

1
これでうまくいきました。私はParameterizedThreadStartとそのバリエーションを試しましたが、喜びがありませんでした。おそらくシンプルなコンソールアプリケーションで.NET Framework 4を使用していました。
Daniel Hollinrake 2014年

これは、この種のデリゲートに慣れている人に最適です。初心者が理解しにくいかもしれません。これはC#標準では問題ありません。受け入れられた答えは私にとってはうまくいきません、そして私にはその理由を見つける時間がありません。
Bitterblue '19年

37
Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param)
{
    string Parameter = (string)param;
}

パラメータタイプはオブジェクトである必要があります。

編集:

この答えは正しくありませんが、このアプローチはお勧めしません。ラムダ式を使用する方が読みやすく、型キャストを必要としません。こちらをご覧くださいhttps : //stackoverflow.com/a/1195915/52551


コンパイルされないコードを手伝うのはなぜParameterですか;) ?
Sebastian XaweryWiśniowiecki

32
class Program
{
    static void Main(string[] args)
    {
        Thread t = new Thread(new ParameterizedThreadStart(ThreadMethod));

        t.Start("My Parameter");
    }

    static void ThreadMethod(object parameter)
    {
        // parameter equals to "My Parameter"
    }
}

3
これにより、「 'DoWork'のオーバーロードはデリゲート 'System.Threading.ParameterizedThreadStart'と一致しません
anon58192932

1
Thread t初期化でThreadMethodを渡しただけの場合、何が違いますか?
ジョー

パラメータタイプは「オブジェクト」タイプでなければなりません
Kunal Uppal

28

そのようにラムダを使用する簡単な方法..

Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();

または、そのようにdelegate使用することもできますThreadStart...

ThreadStart ts = delegate
{
     bool moreWork = DoWork("param1", "param2", "param3");
     if (moreWork) 
     {
          DoMoreWork("param4", "param5");
     }
};
new Thread(ts).Start();

またはVS 2019 .NET 4.5以降を使用すると、さらにクリーンになります。

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING..
    void ts()
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    }
    new Thread(ts).Start();
    //DO SOMETHING..
}



6

ここですでにさまざまな回答で述べられているように、Threadクラス(4.7.2)は現在、いくつかのコンストラクターと、Startオーバーロードを持つメソッドを提供しています。

この質問に関連するこれらのコンストラクタは次のとおりです。

public Thread(ThreadStart start);

そして

public Thread(ParameterizedThreadStart start);

ThreadStartデリゲートまたはデリゲートを取りParameterizedThreadStartます。

対応するデリゲートは次のようになります。

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

見てわかるように、使用する正しいコンストラクターはParameterizedThreadStartデリゲートを取得するコンストラクターであると思われるため、デリゲートの指定されたシグニチャーに準拠するメソッドをスレッドで開始できます。

Threadクラスをインスタンス化する簡単な例は、

Thread thread = new Thread(new ParameterizedThreadStart(Work));

あるいは単に

Thread thread = new Thread(Work);

対応するメソッドのシグネチャ(Workこの例では呼び出されます)は次のようになります。

private void Work(object data)
{
   ...
}

残っているのはスレッドを開始することです。これは、次のいずれかを使用して行われます

public void Start();

または

public void Start(object parameter);

一方でStart()スレッドを開始して渡すnull方法にデータとして、Start(...)渡すために使用することができます何でもWorkのスレッドの方法。

ただし、このアプローチには大きな問題が1つありWorkます。メソッドに渡されるすべてのものがオブジェクトにキャストされます。つまり、Workメソッド内では、次の例のように、元の型に再度キャストする必要があります。

public static void Main(string[] args)
{
    Thread thread = new Thread(Work);

    thread.Start("I've got some text");
    Console.ReadLine();
}

private static void Work(object data)
{
    string message = (string)data; // Wow, this is ugly

    Console.WriteLine($"I, the thread write: {message}");
}



キャスティングは、通常は行いたくないものです。

文字列ではない何かを誰かが渡すとどうなりますか?これは最初は不可能のようです(それは私の方法です、私が何をしているのか、またはメソッドがプライベートであるため、誰かがそれに何かを渡すことができるようにするにはどうすればよいですか?) 。場合によっては問題にならない場合もあれば、問題がある場合もあります。そのような場合InvalidCastException、スレッドを終了するだけなので、おそらく気付かないことになるでしょう。

解決策として、メソッドに渡すデータのタイプがどこにあるかParameterizedThreadStartなどの汎用デリゲートを取得することを期待します。残念ながら、このようなものは存在しません(まだ?)。ParameterizedThreadStart<T>TWork

ただし、この問題には推奨される解決策があります。これには、スレッドに渡されるデータと、次のようなワーカーメソッドを表すメソッドの両方を含むクラスの作成が含まれます。

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

このアプローチでは、次のようにスレッドを開始します。

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

したがって、この方法では、キャストを回避するだけで、スレッドにデータを提供するタイプセーフな方法があります;-)


うわー、コメントなしの反対票...私の答えはキャストと同じくらい悪いのか、読者が私がここで指摘しようとしたことを理解しなかったのか;-)
Markus Safar

1
おめでとうございます。私がすでにNet.Coreで以下をテストし、明示的にキャストする必要なく機能したことを追加したかっただけです!:-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
ポールエフォード

@PaulEffordありがとう;-)あなたの解決策はかなりいいようです。ただし、タイプ固有の情報にはアクセスできません。オブジェクトにボックス化されるからですよね?(例:message.Length不可能など)
Markus Safar

1
右...のような特定のプロパティが必要な場合は、message.GetType()およびキャストできますif(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }。とにかく、代わりに私が使用するビットがより快適見つけ、あなたのスレッドの方法を使用してのTasks<T>、例えばのようにtasks.Add(Task.Run(() => Calculate(par1, par2, par3)))、(以下私の答えを参照stackoverflow.com/a/59777250/7586301を
ポール・Efford

5

渡されたパラメーターに問題がありました。forループから整数を関数に渡して表示しましたが、常に異なる結果が出ました。ParametrizedThreadStartデリゲートを持つ(1,2,2,3)(1,2,3,3)(1,1,2,3)などのように 。

この単純なコードは魅力として機能しました

Thread thread = new Thread(Work);
thread.Start(Parameter);

private void Work(object param) 
{
 string Parameter = (string)param; 
}

4

ParameterizedThreadStartつのパラメータを取ります。これを使用して、1つのパラメータ、または複数のプロパティを含むカスタムクラスを送信できます。

別の方法は、クラスのインスタンスメンバーとして開始するメソッドを、設定するパラメーターのプロパティと共に配置することです。クラスのインスタンスを作成し、プロパティを設定して、インスタンスとメソッドを指定するスレッドを開始すると、メソッドはプロパティにアクセスできます。


3

ParametrizedThreadStartデリゲートを使用できます。

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);


1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 10;
            Thread t1 =new Thread(new ParameterizedThreadStart(order1));
            t1.IsBackground = true;//i can stope 
            t1.Start(x);

            Thread t2=new Thread(order2);
            t2.Priority = ThreadPriority.Highest;
            t2.Start();

            Console.ReadKey();
        }//Main

        static void  order1(object args)
        {
            int x = (int)args;


                for (int i = 0; i < x; i++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write(i.ToString() + " ");
            }
        }

        static void order2()
        {
            for (int i = 100; i > 0; i--)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(i.ToString() + " ");
            }
        }`enter code here`
    }
}

0

Task<T>代わりに使用することを提案しThreadます。それは複数のパラメータを許可し、本当にうまく実行されます。

これが実際の例です:

    public static void Main()
    {
        List<Task> tasks = new List<Task>();

        Console.WriteLine("Awaiting threads to finished...");

        string par1 = "foo";
        string par2 = "boo";
        int par3 = 3;

        for (int i = 0; i < 1000; i++)
        {
            tasks.Add(Task.Run(() => Calculate(par1, par2, par3))); 
        }

        Task.WaitAll(tasks.ToArray());

        Console.WriteLine("All threads finished!");
    }

    static bool Calculate1(string par1, string par2, int par3)
    {
        lock(_locker)
        {
            //...
            return true;
        }
    }

    // if need to lock, use this:
    private static Object _locker = new Object();"

    static bool Calculate2(string par1, string par2, int par3)
    {
        lock(_locker)
        {
            //...
            return true;
        }
    }

-2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ConsoleApp6
{
    class Program
    {
        static void Main(string[] args)
        {

            int x = 10;
            Thread t1 =new Thread(new ParameterizedThreadStart(order1));
            t1.Start(x);

            Thread t2=new Thread(order2);
            t2.Priority = ThreadPriority.Highest;
            t2.Start();

            Console.ReadKey();
        }//Main

        static void  order1(object args)
        {
            int x = (int)args;


            for (int i = 0; i < x; i++)
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.Write(i.ToString() + " ");
            }
        }

        static void order2()
        {
            for (int i = 100; i > 0; i--)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.Write(i.ToString() + " ");
            }
        }
    }
}

C#スレッドを使用したマルチスレッドにより、共有メモリを介して同期するより効率的なアプリケーションを開発できます。
Mohammed Hassen Ismaile 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.