ThreadStart con parámetros

261

¿Cómo iniciar un hilo con parámetros en C #?

JL
fuente
La respuesta a esta pregunta varía ampliamente entre las versiones del tiempo de ejecución.
Quillbreaker
44
Guau. He estado editando algunas de tus preguntas anteriores, pero podría ser un trabajo de tiempo completo. Olvidé cuánto has mejorado con los años. :-)
John Saunders
Si hiciera una pregunta tan breve, obtendría 5 puntuaciones negativas o incluso más. Aunque la pregunta y la respuesta me ayudaron.
Mohammad Musavi

Respuestas:

174

Sí:

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
Erick
fuente
14
es esto lo mismo: ThreadStart processTaskThread = delegate {ProcessTasks (databox.DataboxID); }; nuevo hilo (processTaskThread) .Start ();
JL.
43
¿Qué es myParamObject y myUrl?
dialex
3
En este caso void MyParamObject(object myUrl){ //do stuff }debería tener el tipo de parámetroobject
Elshan
15
-1 porque la respuesta supone que el OP sabe cómo usar ParameterizedThreadStarty claramente del texto de la pregunta, probablemente ese no sea el caso.
JYelton
2
Tengo este error Error CS0123 Ninguna sobrecarga para 'UpdateDB' coincide con el delegado 'ParameterizedThreadStart'
Omid Farvid
482

Una de las 2 sobrecargas del constructor Thread toma un delegado ParameterizedThreadStart que le permite pasar un solo parámetro al método de inicio. Desafortunadamente, solo permite un único parámetro y lo hace de manera insegura porque lo pasa como objeto. Encuentro que es mucho más fácil usar una expresión lambda para capturar los parámetros relevantes y pasarlos de manera fuertemente tipada.

Intenta lo siguiente

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) {
  ...
}
JaredPar
fuente
41
+1: Aunque la respuesta seleccionada actualmente es absolutamente correcta, esta de JaredPar es la mejor. Simplemente es la mejor solución para la mayoría de los casos prácticos.
galaktor
2
Esta solución es mucho mejor que el punto de vista ParameterizedThreadStart
Piotr Owsiak
55
Agradable, muy simple. Simplemente envuelva cualquier llamada en "new Thread (() => FooBar ()) .Start ();
Thomas Jespersen
12
Impresionante, esto es para chicos de VB.NETDim thr As New Thread(Sub() DoStuff(settings))
dr. mal
3
@bavaza Me estaba refiriendo a la comprobación de tipos estáticos
JaredPar
141

Puedes usar expresiones lambda

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

Esta es hasta ahora la mejor respuesta que pude encontrar, es rápida y fácil.

Georgi-it
fuente
66
La mejor solución para casos simples IMO
Dunc
1
¿Qué es eso =>? ¿Y dónde puedo encontrar más información sobre la sintaxis?
Nick
2
Esta es una expresión lambda, se puede encontrar información en estas direcciones: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it
1
Esto funcionó para mí. Probé el ParameterizedThreadStart y sus variaciones, pero no tuve alegría. Estaba usando .NET Framework 4 en una aplicación de consola supuestamente simple.
Daniel Hollinrake
Esto funciona mejor para las personas que están acostumbradas a este tipo de delegados. Puede ser difícil para los principiantes entender. Sin embargo, esto está limpio para los estándares de C #. La respuesta aceptada no funciona para mí y no tengo tiempo para averiguar por qué.
Bitterblue
37
Thread thread = new Thread(Work);
thread.Start(Parameter);

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

El tipo de parámetro debe ser un objeto.

EDITAR:

Si bien esta respuesta no es incorrecta, sí recomiendo este enfoque. Usar una expresión lambda es mucho más fácil de leer y no requiere conversión de tipo. Ver aquí: https://stackoverflow.com/a/1195915/52551

Spencer Ruport
fuente
¿Por qué estás ayudando con un código que no se compila;) Parameter?
Sebastian Xawery Wiś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"
    }
}
huseyint
fuente
3
Esto me está dando "No hay sobrecarga para 'DoWork' coincide con el delegado 'System.Threading.ParameterizedThreadStart'
anon58192932
1
¿Cuál sería la diferencia si acaba de pasar ThreadMethod en la inicialización de Thread t?
Joe
Recuerde, el tipo de parámetro debe ser del tipo 'Objeto'
Kunal Uppal
28

Manera simple usando lambda así ...

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

O incluso podrías delegateusar ThreadStartasí ...

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

O usando VS 2019 .NET 4.5+ incluso más limpio así ...

private void DoSomething(int param1, string param2)
{
    //DO SOMETHING..
    void ts()
    {
        if (param1 > 0) DoSomethingElse(param2, "param3");
    }
    new Thread(ts).Start();
    //DO SOMETHING..
}
Master Mick
fuente
6

Como ya se ha mencionado en varias respuestas aquí, la Threadclase actualmente (4.7.2) proporciona varios constructores y unStart método con sobrecargas.

Estos constructores relevantes para esta pregunta son:

public Thread(ThreadStart start);

y

public Thread(ParameterizedThreadStart start);

que o bien toman un ThreadStartdelegado o unParameterizedThreadStart delegado

Los delegados correspondientes se ven así:

public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);

Como se puede ver, el constructor correcto para usar parece ser el que toma un ParameterizedThreadStart delegado para que el hilo pueda iniciar algún método conforme a la firma especificada del delegado.

Un ejemplo simple para instanciar la Threadclase sería

Thread thread = new Thread(new ParameterizedThreadStart(Work));

o solo

Thread thread = new Thread(Work);

La firma del método correspondiente (llamado Worken este ejemplo) se ve así:

private void Work(object data)
{
   ...
}

Lo que queda es comenzar el hilo. Esto se hace usando cualquiera

public void Start();

o

public void Start(object parameter);

Si bien Start()iniciaría el hilo y pasaría nullcomo datos al método, Start(...)se puede usar para pasar cualquier cosa al Workmétodo del hilo.

Sin embargo, hay un gran problema con este enfoque: todo lo que se pasa al Workmétodo se convierte en un objeto. Eso significa que dentro del Workmétodo tiene que volver al tipo original, como en el siguiente ejemplo:

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}");
}



El casting es algo que normalmente no quieres hacer.

¿Qué pasa si alguien pasa algo más que no es una cadena? Como esto parece no posible al principio (porque es mi método, sé lo que hago o el método es privado, ¿cómo debería alguien ser capaz de pasarle algo? ) Es posible que termine exactamente con ese caso por varias razones . Como algunos casos pueden no ser un problema, otros sí lo son. En tales casos, probablemente terminará con unInvalidCastException que probablemente no notará porque simplemente termina el hilo.

Como solución, esperaría obtener un genérico ParameterizedThreadStart delegado como ParameterizedThreadStart<T>dónde Tsería el tipo de datos que desea pasar al Workmétodo. Desafortunadamente, algo como esto no existe (¿todavía?).

Sin embargo, hay un solución sugerida para este problema. Implica crear una clase que contenga tanto los datos que se pasarán al subproceso como el método que representa el método de trabajo de esta manera:

public class ThreadWithState
{
    private string message;

    public ThreadWithState(string message)
    {
        this.message = message;
    }

    public void Work()
    {
        Console.WriteLine($"I, the thread write: {this.message}");
    }
}

Con este enfoque, comenzaría el hilo de esta manera:

ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);

thread.Start();

Por lo tanto, de esta forma, simplemente evitas dar vueltas y tienes una forma segura de proporcionar datos a un hilo ;-)

Markus Safar
fuente
Wow, un voto negativo sin comentarios ... O mi respuesta es tan mala como el elenco o el lector no entendió lo que intenté señalar aquí ;-)
Markus Safar
1
Encontré su solución muy enlightnen, felicidades. Solo quería agregar que ya lo probé en Net. ¡Tenga en cuenta lo siguiente y trabaje sin tener que explicitar! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford
@PaulEfford Gracias ;-) Su solución parece bastante buena. Pero no tienes acceso para escribir información específica, ya que todavía estará encuadrada en un objeto, ¿verdad? (por ejemplo, message.Lengthno es posible, etc.)
Markus Safar
1
bien ... podría enviar un mensaje. GetType () y emitir si se requiere alguna propiedad específica como if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }. De todos modos, en lugar de usar su método de enhebrado, encontré un poco más cómodo de usar Tasks<T>, como por ejemplo tasks.Add(Task.Run(() => Calculate(par1, par2, par3))), vea mi respuesta a continuación ( stackoverflow.com/a/59777250/7586301 )
Paul Efford
5

Estaba teniendo problemas en el parámetro pasado. Pasé un entero de un bucle for a la función y lo visualicé, pero siempre daba resultados diferentes. como (1,2,2,3) (1,2,3,3) (1,1,2,3), etc. con ParametrizedThreadStart delegado .

este simple código funcionó de maravilla

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

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

los ParameterizedThreadStart toma un parámetro. Puede usar eso para enviar un parámetro o una clase personalizada que contenga varias propiedades.

Otro método es colocar el método que desea comenzar como miembro de la instancia en una clase junto con las propiedades de los parámetros que desea establecer. Cree una instancia de la clase, establezca las propiedades e inicie el hilo especificando la instancia y el método, y el método puede acceder a las propiedades.

Guffa
fuente
3

Puede usar un delegado ParametrizedThreadStart :

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
CMS
fuente
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`
    }
}
Mohammed Hassen Ismaile
fuente
0

Propongo usar en Task<T>lugar de Thread; permite múltiples parámetros y se ejecuta realmente bien.

Aquí hay un ejemplo de trabajo:

    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;
        }
    }
Paul Efford
fuente
-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() + " ");
            }
        }
    }
}
Mohammed Hassen Ismaile
fuente
El subprocesamiento múltiple con subprocesos C # le permite desarrollar aplicaciones más eficientes que se sincronizan a través de la memoria compartida.
Mohammed Hassen Ismaile