ThreadStart com parâmetros


261

Como você inicia um thread com parâmetros em c #?


A resposta a essa pergunta varia muito entre as versões do tempo de execução - uma resposta de 3,5 é boa?
28510 quillbreaker

4
Uau. Venho editando algumas de suas perguntas antigas, mas pode ser um trabalho de período integral. Eu tinha esquecido o quanto você melhorou ao longo dos anos. :-)
John Saunders

Se eu fizesse uma pergunta tão breve, obteria 5 pontos negativos ou mais! Embora a pergunta e a resposta tenham me ajudado.
Mohammad Musavi

Respostas:


174

Sim :

Thread t = new Thread (new ParameterizedThreadStart(myMethod));
t.Start (myParameterObject);

14
é o mesmo: ThreadStart processTaskThread = delegate {ProcessTasks (databox.DataboxID); }; novo Thread (processTaskThread) .Start ();
JL.

43
O que são myParamObject e myUrl?
Dia28

3
Nesse caso, void MyParamObject(object myUrl){ //do stuff }deve ter o tipo de parâmetroobject
Elshan 24/10

15
-1 porque a resposta supõe que o OP sabe usar ParameterizedThreadStarte claramente do texto da pergunta, provavelmente não é esse o caso.
JYelton

2
Eu tenho esse erro Erro CS0123 Nenhuma sobrecarga para 'UpdateDB' corresponde ao delegado 'ParameterizedThreadStart'
Omid Farvid

482

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) {
  ...
}

41
+1: mesmo que a resposta atualmente selecionada esteja absolutamente correta, esta da JaredPar é a melhor. Simplesmente é a melhor solução para os casos mais práticos.
galaktor

2
Esta solução é muito melhor que a padrão ParameterizedThreadStart #
Piotr Owsiak

5
Bom, tão simples. Basta encerrar qualquer chamada em "new Thread (() => FooBar ()) .Start ();
Thomas Jespersen

12
Impressionante, isso é para o pessoal do VB.NETDim thr As New Thread(Sub() DoStuff(settings))
dr. mal

3
@bavaza eu estava apenas se referindo ao tipo estático verificação
JaredPar

141

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.


6
Melhor solução para casos simples IMO
Dunc 12/04/2013

1
o que é isso =>? e onde posso encontrar mais informações sobre a sintaxe?
Nick

2
Esta é uma expressão lambda, algumas informações podem ser encontradas nesses endereços: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it

1
Isso funcionou para mim. Eu tentei o ParameterizedThreadStart e variações dele, mas não tive alegria. Eu estava usando o .NET Framework 4 em um aplicativo de console supostamente simples.
Daniel Hollinrake

Isso funciona melhor para pessoas acostumadas a esse tipo de delegado. Pode ser difícil para os iniciantes entenderem. Isso é limpo para os padrões C #. A resposta aceita não funciona para mim e não tenho tempo para descobrir o porquê.
Bitterblue

37
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


Por que você está ajudando com um código que não 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"
    }
}

3
Isso está me dando "Nenhuma sobrecarga para 'DoWork' corresponde ao delegado 'System.Threading.ParameterizedThreadStart'
anon58192932

1
Qual seria a diferença se você passasse o ThreadMethod na inicialização do Thread t?
21414 Joe

Lembre-se, o tipo de parâmetro deve ser do tipo 'Objeto'
Kunal Uppal

28

Maneira simples usando lambda assim ..

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

Ou você pode até delegateusar ThreadStartassim ...

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..
}



6

Como já foi mencionado em várias respostas aqui, a Threadclasse atualmente (4.7.2) fornece vários construtores e um Startmétodo com sobrecargas.

Esses construtores relevantes para esta pergunta são:

public Thread(ThreadStart start);

e

public Thread(ParameterizedThreadStart start);

que leva um ThreadStartdelegado ou um ParameterizedThreadStartdelegado.

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 ParameterizedThreadStartdelegado, para que algum método em conformidade com a assinatura especificada do delegado possa ser iniciado pelo encadeamento.

Um exemplo simples para instanciar a Threadclasse seria

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

ou apenas

Thread thread = new Thread(Work);

A assinatura do método correspondente (chamada Workneste 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 nullcomo dados para o método, Start(...)pode ser usado para passar qualquer coisa para o Workmétodo do encadeamento.

No entanto, há um grande problema com essa abordagem: tudo o Workque é passado no método é convertido em um objeto. Isso significa que, dentro do Workmé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 InvalidCastExceptionque provavelmente não notará porque simplesmente encerra o encadeamento.

Como solução, você esperaria obter um ParameterizedThreadStartrepresentante genérico como ParameterizedThreadStart<T>onde Tseria o tipo de dados que você deseja passar para o Workmé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 ;-)


Uau, um downvote sem comentários ... Ou a minha resposta é tão ruim quanto o elenco ou o leitor não entendeu o que eu tentei salientar aqui ;-)
Markus Safar

1
Achei sua solução muito esclarecida, parabéns. Só queria acrescentar que eu já testei no Net.Core o seguinte e trabalhei sem precisar explicitar o elenco! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford 15/01

@PaulEfford Obrigado ;-) Sua solução parece bastante agradável. Mas você não tem acesso ao tipo de informações específicas, pois elas ainda serão encaixotadas em um objeto, certo? (por exemplo, message.Lengthnão é possível e assim por diante)
Markus Safar

1
right ... você poderia message.GetType () e cast se necessário uma propriedade específica como 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 )
Paul Efford

5

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

4

O ParameterizedThreadStartleva 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.


3

Você pode usar um delegado ParametrizedThreadStart :

string parameter = "Hello world!";
Thread t = new Thread(new ParameterizedThreadStart(MyMethod));
t.Start(parameter);


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`
    }
}

0

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

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

A multiencadeamento com threads em C # permite desenvolver aplicativos mais eficientes, sincronizados através da memória compartilhada.
Mohammed Hassen Ismaile
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.