【问题标题】:ThreadStart with parameters带参数的ThreadStart
【发布时间】:2009-07-28 18:31:35
【问题描述】:

如何在 C# 中启动带参数的线程?

【问题讨论】:

  • 这个问题的答案在不同版本的运行时差异很大 - 3.5 答案好吗?
  • 哇。我一直在编辑你的一些老问题,但这可能是一份全职工作。我忘记了,呃,这些年来你进步了多少。 :-)
  • 如果我问这样一个简短的问题,我会得到 5 个负分甚至更多!虽然问答对我有帮助。

标签: c# multithreading


【解决方案1】:

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

【讨论】:

  • +1:尽管当前选择的答案是绝对正确的,但 JaredPar 的这个答案更好。对于大多数实际情况来说,它是最好的解决方案。
  • 这个解决方案比标准的ParameterizedThreadStart好得多
  • 好简单。只需将任何调用包装在“new Thread(() => FooBar()).Start();
  • 太棒了,这是给 VB.NET 的人Dim thr As New Thread(Sub() DoStuff(settings))
  • @bavaza 我只是指静态类型检查
【解决方案2】:

是的:

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

【讨论】:

  • 是不是一样的:ThreadStart processTaskThread = delegate { ProcessTasks(databox.DataboxID ); };新线程(processTaskThread).Start();
  • 什么是 myParamObject 和 myUrl?
  • 在这种情况下void MyParamObject(object myUrl){ //do stuff }应该有参数类型object
  • -1 因为答案假设 OP 知道如何使用 ParameterizedThreadStart 并且从问题文本中清楚地看出,情况可能并非如此。
  • 我有这个错误 错误 CS0123 'UpdateDB' 没有重载匹配委托 'ParameterizedThreadStart'
【解决方案3】:

你可以使用 lambda 表达式

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

这是迄今为止我能找到的最佳答案,它既快速又简单。

【讨论】:

  • 简单案例IMO的最佳解决方案
  • 那是什么 =>?我在哪里可以找到有关语法的更多信息?
  • 这是一个 lambda 表达式,可以在以下地址找到一些信息:msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
  • 这对我有用。我尝试了 ParameterizedThreadStart 及其变体,但没有任何乐趣。我在一个简单的控制台应用程序中使用 .NET Framework 4。
  • 这对习惯了这类代表的人来说效果最好。初学者可能难以理解。不过,这对于 C# 标准来说是干净的。接受的答案对我不起作用,我没有时间找出原因。
【解决方案4】:
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
【解决方案5】:
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"
    }
}

【讨论】:

  • 这给了我“'DoWork' 没有重载匹配委托 'System.Threading.ParameterizedThreadStart'
  • 如果只是在 Thread t 初始化中传递 ThreadMethod 会有什么不同?
  • 记住,参数类型必须是'Object'类型
【解决方案6】:

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

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

或者你甚至可以像这样使用ThreadStart delegate...

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

OR 使用 .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..
}

【讨论】:

    【解决方案7】:

    正如这里的各种答案中已经提到的那样,Thread 类目前(4.7.2)提供了几个 constructors 和一个 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 方法。 p>

    然而,这种方法存在一个大问题: 传入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>,其中T 是您要传递给Work 方法的数据类型。不幸的是,这样的东西不存在(还没有?)。

    然而,这个问题有一个suggested solution。它涉及创建一个类,该类包含要传递给线程的数据以及表示工作方法的方法,如下所示:

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

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

    【讨论】:

    • 哇,没有评论的投反对票......要么我的回答和演员一样糟糕,要么读者不明白我在这里试图指出的内容;-)
    • 我发现您的解决方案非常有启发性,恭喜。只是想补充一点,我已经在 Net.Core 中测试了以下内容,并且无需显式转换即可工作! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
    • @PaulEfford 谢谢 ;-) 你的解决方案看起来很不错。但是您无法访问特定类型的信息,因为它仍会被装箱到对象中,对吗? (例如message.Length 是不可能的等等)
    • 对...如果需要任何特定属性,例如if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; },您可以使用 message.GetType() 并进行转换。无论如何,而不是使用你的线程方法,我发现使用Tasks<T> 更舒服,例如tasks.Add(Task.Run(() => Calculate(par1, par2, par3))),请参阅下面的答案(stackoverflow.com/a/59777250/7586301
    【解决方案8】:

    我在传递的参数中遇到问题。 我将整数从 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; 
    }
    

    【讨论】:

      【解决方案9】:

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

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

      【讨论】:

        【解决方案10】:

        您可以使用ParametrizedThreadStart 委托:

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

        【讨论】:

          【解决方案11】:

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

          【讨论】:

            【解决方案12】:
            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`
                }
            }
            

            【讨论】:

              【解决方案13】:

              我建议使用Task&lt;T&gt;而不是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;
                      }
                  }
              

              【讨论】:

                【解决方案14】:

                使用 lambda 表达式的一个非常简单方便的方法可以是这样的:

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

                这样 lambda 表达式可以有参数并在单独的线程中运行内联代码。

                【讨论】:

                  【解决方案15】:
                  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# 线程的多线程允许您开发更高效的应用程序,通过共享内存进行同步。
                  猜你喜欢
                  • 2012-11-06
                  • 2011-03-22
                  • 1970-01-01
                  • 2013-12-20
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多