ThreadStart with parameters


261

如何使用C#中的参数启动线程?


这个问题的答案在运行时的各个版本之间差异很大-3.5的答案好吗?
quillbreaker

4
哇。我一直在编辑您的一些旧问题,但这可能是一份全职工作。我忘记了,这些年来你有多少进步。:-)
约翰·桑德斯

如果我问这样一个简短的问题,我将获得5分甚至更高的负分!虽然问题和答案帮助了我。
Mohammad Musavi

Answers:


174

是的:

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

14
是否相同:ThreadStart processTaskThread =委托{ProcessTasks(databox.DataboxID); }; new Thread(processTaskThread).Start();
JL。

43
什么是myParamObject和myUrl?
Dialex 2012年

3
在这种情况下,void MyParamObject(object myUrl){ //do stuff }应具有参数类型object
Elshan 2014年

15
-1,因为答案假设OP知道如何使用ParameterizedThreadStart并且可以从问题文本中清楚地知道,事实并非如此。
JYelton

2
我有这样的错误错误CS0123无过载为“定时所匹配的委托“ParameterizedThreadStart”
奥米德Farvid

482

Thread构造函数的2个重载之一重载了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) {
  ...
}

41
+1:即使当前选择的答案是绝对正确的,JaredPar提出的答案也是更好的答案。对于大多数实际情况而言,它只是最佳的解决方案。
galaktor

2
这个解决方案比标准的ParameterizedThreadStart好
Piotr Owsiak 2010年

5
很好,很简单。只需将任何调用包装在“ new Thread(()=> FooBar()).Start();
Thomas Jespersen 2010年

12
真棒,这是VB.NET家伙Dim thr As New Thread(Sub() DoStuff(settings))
博士。邪恶的

3
@bavaza我只是指静态类型检查
JaredPar

141

您可以使用lambda表达式

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

到目前为止,这是我能找到的最佳答案,它既快速又容易。


6
简单案例的最佳解决方案IMO
Dunc

1
那是什么=>?在哪里可以找到有关语法的更多信息?
尼克,

2
这是一个lambda表达式,可以在以下地址上找到一些信息: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

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

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

参数类型必须是一个对象。

编辑:

虽然这个答案不是正确的,但我还是建议不要使用这种方法。使用lambda表达式更容易阅读,并且不需要类型转换。看到这里: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 2013年

1
如果您只是在Thread t初始化中传递ThreadMethod,会有什么区别?

记住,参数类型必须是的“对象”类型
注:Kunal Uppal

28

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

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给线程的方法。

但是,这种方法存在一个大问题:传递给该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

但是,有针对此问题的建议解决方案。它涉及创建一个类,该类既包含要传递给线程的数据,又包含表示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();

因此,以这种方式,您只需避免进行转换,并具有将数据提供给线程的类型安全方式;-)


哇,毫无评论可言...我的回答和演员表一样糟糕,或者读者听不懂我想在这里指出的内容;-)
马库斯·萨法尔

1
恭喜,我发现您的解决方案很有启发性。只是想补充一点,我已经在Net.Core中测试了以下内容,并且无需显式转换即可工作!:-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford

@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循环中将整数传递给函数并显示它,但是它总是给出不同的结果。像(1,2,2,3)(1,2,3,3)(1,1,2,3)一样,使用 ParametrizedThreadStart委托。

这个简单的代码很吸引人

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

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

4

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

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




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#线程的多线程可让您开发更有效的应用程序,并通过共享内存进行同步。
穆罕默德·哈森·伊斯梅勒
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.