【问题标题】:How to pass parameters to ThreadStart method in Thread?如何将参数传递给 Thread 中的 ThreadStart 方法?
【发布时间】:2011-03-22 14:13:58
【问题描述】:

C#中如何给Thread.ThreadStart()方法传递参数?

假设我有一个名为“下载”的方法

public void download(string filename)
{
    // download code
}

现在我在 main 方法中创建了一个线程:

Thread thread = new Thread(new ThreadStart(download(filename));

预期的错误方法类型。

如何使用带参数的目标方法将参数传递给ThreadStart

【问题讨论】:

  • 查看由 Jon Skeet 撰写的 this 文章 参数部分在下一页,但整篇文章读起来很不错。

标签: c# .net multithreading


【解决方案1】:

最简单的就是

string filename = ...
Thread thread = new Thread(() => download(filename));
thread.Start();

这样做的优点(超过ParameterizedThreadStart)是您可以传递多个参数,并且无需一直从object 转换即可获得编译时检查。

【讨论】:

  • 我很抱歉跑题了,但'()' 运算符是什么意思?我有时会看到它,但我没有时间检查。
  • 这是一个没有参数的 lambda 表达式。
  • @ŁukaszW.pl - Noldorin 所说的 ;p 在 C# 2.0 中,一个替代构造(对于这个例子)是 new Thread(delegate() { download(filename); });
  • @Tymek 这不是相当准确;捕获的任何变量都被视为完整的词法闭包,它(作为实现细节)被实现为编译器生成的类上的字段。此外,闭包范围被定义为声明范围。它并不是真正的“作为引用”(“按引用传递”和“引用类型”都定义明确,并且都没有真正描述这种情况)
  • @MarcGravell - 你是对的。我应该说的是,如果“文件名”在线程启动之前发生更改,则将使用新值。我不应该喋喋不休地谈论它的机制,我绝对不应该谈论引用。
【解决方案2】:

看这个例子:

public void RunWorker()
{
    Thread newThread = new Thread(WorkerMethod);
    newThread.Start(new Parameter());
}

public void WorkerMethod(object parameterObj)
{
    var parameter = (Parameter)parameterObj;
    // do your job!
}

您首先通过将委托传递给工作方法来创建一个线程,然后使用 Thread.Start 方法启动它,该方法将您的对象作为参数。

所以在你的情况下你应该像这样使用它:

    Thread thread = new Thread(download);
    thread.Start(filename);

但是您的“下载”方法仍然需要将 object,而不是 string 作为参数。您可以将其转换为方法体中的字符串。

【讨论】:

    【解决方案3】:

    您希望将ParameterizedThreadStart 委托用于接受参数的线程方法。 (或者实际上根本没有,让Thread 构造函数推断。)

    示例用法:

    var thread = new Thread(new ParameterizedThreadStart(download));
    //var thread = new Thread(download); // equivalent
    
    thread.Start(filename)
    

    【讨论】:

      【解决方案4】:

      你也可以像这样delegate...

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

      【讨论】:

        【解决方案5】:

        附加

            Thread thread = new Thread(delegate() { download(i); });
            thread.Start();
        

        【讨论】:

          【解决方案6】:

          我会建议你有另一个名为 File 的类。

          public class File
          {
             private string filename;
          
             public File(string filename)
             {
                this.filename= filename;
             }
          
             public void download()
             {
                 // download code using filename
             }
          }
          

          在你的线程创建代码中,你实例化了一个新文件:

          string filename = "my_file_name";
          
          myFile = new File(filename);
          
          ThreadStart threadDelegate = new ThreadStart(myFile.download);
          
          Thread newThread = new Thread(threadDelegate);
          

          【讨论】:

          • 好久不见了。
          【解决方案7】:

          您可以将线程函数(下载)和所需参数(文件名)封装在一个类中,并使用 ThreadStart 委托来执行线程函数。

          public class Download
          {
              string _filename;
          
              Download(string filename)
              {
                 _filename = filename;
              }
          
              public void download(string filename)
              {
                 //download code
              }
          }
          
          Download = new Download(filename);
          Thread thread = new Thread(new ThreadStart(Download.download);
          

          【讨论】:

          • 我更喜欢这种方法,我发现 lambda 表达式方法并不总是跟踪正确的参数
          【解决方案8】:

          这个怎么样:(或者这样用可以吗?)

          var test = "Hello";
          new Thread(new ThreadStart(() =>
          {
              try
              {
                  //Staff to do
                  Console.WriteLine(test);
              }
              catch (Exception ex)
              {
                  throw;
              }
          })).Start();
          

          【讨论】:

            【解决方案9】:

            根据你的问题...

            C#中如何给Thread.ThreadStart()方法传递参数?

            ...以及您遇到的错误,您必须从

            更正您的代码
            Thread thread = new Thread(new ThreadStart(download(filename));
            

            Thread thread = new Thread(new ThreadStart(download));
            thread.Start(filename);
            



            不过,这个问题看起来更复杂。

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

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

            【讨论】:

              【解决方案10】:

              这是最完美的方式...

              private void func_trd(String sender)
              {
              
                  try
                  {
                      imgh.LoadImages_R_Randomiz(this, "01", groupBox, randomizerB.Value); // normal code
              
                      ThreadStart ts = delegate
                      {
                          ExecuteInForeground(sender);
                      };
              
                      Thread nt = new Thread(ts);
                      nt.IsBackground = true;
              
                      nt.Start();
              
                  }
                  catch (Exception)
                  {
              
                  }
              }
              
              private void ExecuteInForeground(string name)
              {
                   //whatever ur function
                  MessageBox.Show(name);
              }
              

              【讨论】:

                猜你喜欢
                • 2011-08-09
                • 2012-11-06
                • 2010-10-16
                • 2012-05-19
                • 2016-04-16
                • 2011-07-18
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多