¿Cómo iniciar un hilo con parámetros en C #?
¿Cómo iniciar un hilo con parámetros en C #?
Respuestas:
Sí:
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
debería tener el tipo de parámetroobject
ParameterizedThreadStart
y claramente del texto de la pregunta, probablemente ese no sea el caso.
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) {
...
}
Dim thr As New Thread(Sub() DoStuff(settings))
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.
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
Parameter
?
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"
}
}
Manera simple usando lambda así ...
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
O incluso podrías delegate
usar ThreadStart
así ...
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..
}
Como ya se ha mencionado en varias respuestas aquí, la Thread
clase 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 ThreadStart
delegado 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 Thread
clase sería
Thread thread = new Thread(new ParameterizedThreadStart(Work));
o solo
Thread thread = new Thread(Work);
La firma del método correspondiente (llamado Work
en 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 null
como datos al método, Start(...)
se puede usar para pasar cualquier cosa al Work
método del hilo.
Sin embargo, hay un gran problema con este enfoque: todo lo que se pasa al Work
método se convierte en un objeto. Eso significa que dentro del Work
mé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 T
sería el tipo de datos que desea pasar al Work
mé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 ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
no es posible, etc.)
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 )
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;
}
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.
Puede usar un delegado ParametrizedThreadStart :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Puede usar el método BackgroundWorker RunWorkerAsync y pasar su valor.
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`
}
}
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;
}
}
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() + " ");
}
}
}
}