带参数的ThreadStart

如何在c#中使用参数启动线程?

432142 次浏览

是的:

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

Thread构造函数的两个重载之一采用ParameterizedThreadStart委托,允许您将单个参数传递给start方法。不幸的是,虽然它只允许一个参数,它这样做的方式是不安全的,因为它传递作为对象。我发现使用lambda表达式捕获相关参数并以强类型的方式传递它们要容易得多。

试试下面的方法

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) {
...
}
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"
}
}

你可以使用ParametrizedThreadStart委托:

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

ParameterizedThreadStart接受一个参数。您可以使用它来发送一个参数或包含多个属性的自定义类。

另一种方法是将想要启动的方法作为实例成员放在类中,并将其与想要设置的参数的属性放在一起。创建类的实例,设置属性并启动指定实例和方法的线程,这样方法就可以访问属性。

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


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

参数类型必须为对象。

编辑:

虽然这个答案是正确的,但我不建议使用这种方法。使用lambda表达式更容易阅读,并且不需要类型强制转换。看这里:https://stackoverflow.com/a/1195915/52551

你可以使用BackgroundWorker RunWorkerAsync方法并传入你的值。

你可以使用lambda表达式

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

这是目前为止我能找到的最好的答案,又快又简单。

我在传递的参数中有问题。 我将一个整数从for循环传递给函数并显示它,但它总是给出不同的结果。(1、2、2、3)(1、2、3、3)(1,1,2,3)与< em > ParametrizedThreadStart < / em >委托等。< / p >

这个简单的代码很有魔力

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


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

使用lambda的简单方法是这样的..

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

你甚至可以使用ThreadStartdelegate,像这样…

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

使用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..
}
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() + " ");
}
}
}
}
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`
}
}

正如在这里的各种回答中已经提到的,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方法。

然而,这种方法有一个大问题: 传递给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}");
}
< p > < br > < br > 强制转换通常是您不想做的事情。 < br > < br > 如果有人传递其他不是字符串的东西怎么办?因为一开始这似乎是不可能的(因为这是我的方法,我知道我在做什么方法是私有的,怎么能有人把东西传递给它呢?),你可能会因为各种原因而最终出现这种情况。有些情况下可能不是问题,其他情况则是。在这种情况下,你可能会得到InvalidCastException,你可能不会注意到,因为它只是结束了线程

作为一种解决方案,你会期望获得一个通用的ParameterizedThreadStart委托,如ParameterizedThreadStart<T>,其中T将是你想传递给Work方法的数据类型。不幸的是,这样的东西还不存在(目前?)

然而,这个问题有一个建议的解决方案。它涉及到创建一个类,其中包含传递给线程的数据以及表示worker方法的方法,如下所示:

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();

因此,通过这种方式,您可以简单地避免强制转换,并以类型安全的方式向线程提供数据;-)

我建议使用__abc0代替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;
}
}

使用lambda表达式的一种非常简单和方便的方式是这样的:

Thread thread = new Thread( (param) => {
string name = param as string;
// rest of code goes here.
});
thread.Start("MyName");

通过这种方式,lambda表达式可以具有参数并在单独的线程中运行内联代码。