Como você inicia um thread com parâmetros em c #?
Como você inicia um thread com parâmetros em c #?
Respostas:
Sim :
Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);
void MyParamObject(object myUrl){ //do stuff }
deve ter o tipo de parâmetroobject
ParameterizedThreadStart
e claramente do texto da pergunta, provavelmente não é esse o caso.
Uma das 2 sobrecargas do construtor Thread leva um delegado ParameterizedThreadStart, que permite passar um único parâmetro ao método start. Infelizmente, embora ele permita apenas um único parâmetro e o faça de maneira insegura, porque passa como objeto. Acho muito mais fácil usar uma expressão lambda para capturar os parâmetros relevantes e transmiti-los de maneira fortemente tipada.
Tente o seguinte
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))
Você pode usar expressões lambda
private void MyMethod(string param1,int param2)
{
//do stuff
}
Thread myNewThread = new Thread(() => MyMethod("param1",5));
myNewThread.Start();
Até agora, essa é a melhor resposta que pude encontrar, é rápida e fácil.
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
O tipo de parâmetro deve ser um objeto.
EDITAR:
Embora essa resposta não esteja incorreta, recomendo essa abordagem. Usar uma expressão lambda é muito mais fácil de ler e não requer conversão de tipo. Veja aqui: 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"
}
}
Maneira simples usando lambda assim ..
Thread t = new Thread(() => DoSomething("param1", "param2"));
t.Start();
Ou você pode até delegate
usar ThreadStart
assim ...
ThreadStart ts = delegate
{
bool moreWork = DoWork("param1", "param2", "param3");
if (moreWork)
{
DoMoreWork("param4", "param5");
}
};
new Thread(ts).Start();
OU usando o VS 2019 .NET 4.5+ ainda mais limpo assim ..
private void DoSomething(int param1, string param2)
{
//DO SOMETHING..
void ts()
{
if (param1 > 0) DoSomethingElse(param2, "param3");
}
new Thread(ts).Start();
//DO SOMETHING..
}
Como já foi mencionado em várias respostas aqui, a Thread
classe atualmente (4.7.2) fornece vários construtores e um Start
método com sobrecargas.
Esses construtores relevantes para esta pergunta são:
public Thread(ThreadStart start);
e
public Thread(ParameterizedThreadStart start);
que leva um ThreadStart
delegado ou um ParameterizedThreadStart
delegado.
Os delegados correspondentes ficam assim:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
Portanto, como pode ser visto, o construtor correto a ser usado parece ser aquele que recebe um ParameterizedThreadStart
delegado, para que algum método em conformidade com a assinatura especificada do delegado possa ser iniciado pelo encadeamento.
Um exemplo simples para instanciar a Thread
classe seria
Thread thread = new Thread(new ParameterizedThreadStart(Work));
ou apenas
Thread thread = new Thread(Work);
A assinatura do método correspondente (chamada Work
neste exemplo) se parece com isso:
private void Work(object data)
{
...
}
O que resta é iniciar o thread. Isso é feito usando qualquer um
public void Start();
ou
public void Start(object parameter);
Enquanto Start()
iniciaria o encadeamento e passaria null
como dados para o método, Start(...)
pode ser usado para passar qualquer coisa para o Work
método do encadeamento.
No entanto, há um grande problema com essa abordagem: tudo o Work
que é passado no método é convertido em um objeto. Isso significa que, dentro do Work
método, ele deve ser convertido para o tipo original novamente, como no exemplo a seguir:
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}");
}
A transmissão é algo que você normalmente não deseja fazer.
E se alguém passa outra coisa que não é uma string? Como isso parece impossível no início (porque é o meu método, eu sei o que faço ou O método é privado, como alguém deve ser capaz de transmitir alguma coisa a ele? ), Você pode acabar exatamente com esse caso por vários motivos . Como alguns casos podem não ser um problema, outros são. Nesses casos, você provavelmente terminará com um InvalidCastException
que provavelmente não notará porque simplesmente encerra o encadeamento.
Como solução, você esperaria obter um ParameterizedThreadStart
representante genérico como ParameterizedThreadStart<T>
onde T
seria o tipo de dados que você deseja passar para o Work
método. Infelizmente, algo assim não existe (ainda?).
Existe, no entanto, uma solução sugerida para esse problema. Envolve a criação de uma classe que contém os dados a serem passados para o encadeamento, bem como o método que representa o método worker como este:
public class ThreadWithState
{
private string message;
public ThreadWithState(string message)
{
this.message = message;
}
public void Work()
{
Console.WriteLine($"I, the thread write: {this.message}");
}
}
Com essa abordagem, você iniciaria o thread assim:
ThreadWithState tws = new ThreadWithState("I've got some text");
Thread thread = new Thread(tws.Work);
thread.Start();
Portanto, dessa maneira, você simplesmente evita transmitir e tem uma maneira segura de fornecer dados a um thread ;-)
private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
message.Length
não é possível e assim por diante)
if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }
. Enfim, em vez de usar seu método de encadeamento, achei um pouco mais confortável de usar Tasks<T>
, como por exemplo tasks.Add(Task.Run(() => Calculate(par1, par2, par3)))
, veja minha resposta abaixo ( stackoverflow.com/a/59777250/7586301 )
Eu estava tendo problema no parâmetro passado. Passei o número inteiro de um loop for para a função e a exibi, mas ela sempre dava resultados diferentes. like (1,2,2,3) (1,2,3,3) (1,1,2,3) etc com o delegado ParametrizedThreadStart .
esse código simples funcionou como um encanto
Thread thread = new Thread(Work);
thread.Start(Parameter);
private void Work(object param)
{
string Parameter = (string)param;
}
O ParameterizedThreadStart
leva um parâmetro. Você pode usar isso para enviar um parâmetro ou uma classe personalizada contendo várias propriedades.
Outro método é colocar o método que você deseja iniciar como membro da instância em uma classe, juntamente com as propriedades dos parâmetros que você deseja definir. Crie uma instância da classe, defina as propriedades e inicie o thread especificando a instância e o método, e o método poderá acessar as propriedades.
Você pode usar um delegado ParametrizedThreadStart :
string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);
Você pode usar o método BackgroundWorker RunWorkerAsync e transmitir seu 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`
}
}
Eu proponho usar em Task<T>
vez de Thread
; permite vários parâmetros e executa muito bem.
Aqui está um exemplo de trabalho:
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() + " ");
}
}
}
}