如何在C#中将参数传递给线程?

时间:2013-12-06 13:25:36

标签: c# multithreading

请考虑以下代码:

namespace MyThreads
{
    public class HisThread
    {
        public int Thread2(int start, int end, int[] arr)
        {
            int sum = 0;
            // foreach (int i in arr)
            for (int i = start; i <= end; i++)
            {
                sum += arr[i];
            }
            return sum;
        }

    }


    public class MyThread
    {
        public void Thread1()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine("Hello world " + i);
                Thread.Sleep(1);
            }
        }
    }


    public class Test
    {

        public static void Main()
        {
            int[] arr = new int[30];
            for (int i = 0; i < 30; i++ )
            {
                arr[i] = i;
            }

            Console.WriteLine("Before start thread");

            // thread 1 - without params
            MyThread thr = new MyThread();
            Thread tid1 = new Thread(new ThreadStart(thr.Thread1)); // this one is OK
            tid1.Start();

            // thread 2 - with params
            HisThread thr2 = new HisThread();
            Thread tid2 = new Thread(new ParameterizedThreadStart(thr2.Thread2));
        }
    }

}

第一个线程编译正常(没有参数),但第二个线程生成

Error 1 No overload for 'Thread2' matches delegate 

知道如何解决这个问题吗?

由于

7 个答案:

答案 0 :(得分:3)

ParameterizedThreadStart委托要求接受object类型的单个参数的方法:

public delegate void ParameterizedThreadStart(object obj)

即。你的方法应该是

public class HisThread
{
    public void Thread2(object obj)
    {
        // ...
    }
}

还有方法Thread.Start接受参数:

 // thread 2 - with params
 HisThread thr2 = new HisThread();
 Thread tid2 = new Thread(new ParameterizedThreadStart(thr2.Thread2));
 tid2.Start(parameter);

如果您使用的是.NET 4.5,则可以改为使用tasks

 Task<int>.Run(() => thr2.Thread2(start, end, array))

答案 1 :(得分:2)

Thread thr2 = new Thread(() => thr2.Thread2(0, 1, arr));

但是,如果你在调用之后立即调整变量,它会产生一些副作用,因为你是通过引用有效地传递变量的。

答案 2 :(得分:2)

试试这个:

Thread thread = new Thread(() => new HisThread().Thread2(0, 3, new int[] { 1, 2, 3, 4 }));

如果你在2.0:

Thread thread = new Thread(delegate() { new HisThread().Thread2(0, 3, new int[] { 1, 2, 3, 4 }); });

答案 3 :(得分:1)

这可能会有所帮助:

class MyParameter
{
    public int Start, End; //Use Properties for these
    public int[] Array;    //Use Properties for this
}

然后:

 // thread 2 - with params
 HisThread thr2 = new HisThread();
 Thread tid2 = new Thread(new ParameterizedThreadStart(p =>
 {
     var temp = (MyParameter)p;
     thr2.Thread2(temp.Start, temp.End, temp.Array);
 }));

 tid2.Start(new Parameter(1, 10, yourArray));

答案 4 :(得分:1)

该代码的问题在于ParameterizedThreadStart是委托类型,这意味着它与特定的方法签名相关联 - 特别是该签名是void method(object)。您的方法Thread2与该签名不匹配,因此编译错误。

那怎么解决呢?这完全取决于。

ParameterizedThreadStart具有该签名,因为它是有史以来最通用的方法。它背后的想法是你可以传递一个包含你的函数需要的所有状态的自定义类型的对象,如下所示:

class Params
{
    public int Start { get; set; }
    public int End { get; set; }
    public int[] Array { get; set; }
}

var p = new Params { 0, 0, new int[0] };
var t = new Thread(thr2.Thread2);
t.Start(p);

public int Thread2(object param)
{
    var p = (Params)param;
    // and now get your arguments as p.Start etc.
}

虽然这有效,但它很笨拙,迫使你放弃Thread2最自然的签名。但是你可以通过插入一个匿名函数来做更好的参数解压缩来做得更好:

int start = 0, end = 0;
var arr = new int[0];
var t = new Thread(() => thr2.Thread2(start, end, arr));

如果您选择这样做,您必须注意这样一个事实,即由于编译器用于将参数传递给线程方法的机制,在t定义之后但在启动之前更改它们的值将使Thread2看到更改的值。

答案 5 :(得分:1)

  

为什么不编译?

因为您的代理与所需的签名不符。

  

知道如何解决这个问题吗?

<强>解决方法1: 创建自己的类型并传递数据

public class MyClass
{
    public int start {get;set;};
    public int end {get;set;};
    public int[] arr {get;set;};
}

public void Thread2(object parameter)
{
    MyClass obj = (MyClass)parameter;
    //Make use of obj
}

HisThread thr2 = new HisThread();
Thread tid2 = new Thread(new ParameterizedThreadStart(thr2.Thread2));
tid2.Start(new MyClass{...});

<强>溶液2: 只需使用lambda

HisThread thr2 = new HisThread();
Thread tid2 = new Thread(() => thr2.Thread2(param1,param2,param3));
tid2.Start();

答案 6 :(得分:0)

最简单的是delegate这样......

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