ThreadStart con parametri


261

Come si avvia una discussione con parametri in C #?


La risposta a questa domanda varia ampiamente tra le versioni del runtime: una risposta 3.5 va bene?
Quillbreaker,

4
Wow. Ho modificato alcune delle tue vecchie domande, ma potrebbe essere un lavoro a tempo pieno. Avevo dimenticato quanto sei migliorato nel corso degli anni. :-)
John Saunders il

Se facessi una domanda così breve otterrei 5 punteggi negativi o anche di più! Anche se la domanda e la risposta mi hanno aiutato.
Mohammad Musavi,

Risposte:


174

Sì:

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

14
è lo stesso: ThreadStart processTaskThread = delegate {ProcessTasks (databox.DataboxID); }; nuovo thread (processTaskThread) .Start ();
JL.

43
Che cos'è myParamObject e myUrl?
dialex,

3
In questo caso void MyParamObject(object myUrl){ //do stuff }dovrebbe avere il tipo di parametroobject
Elshan,

15
-1 perché la risposta presuppone che l'OP sappia usare ParameterizedThreadStarte chiaramente dal testo della domanda, probabilmente non è così.
JYelton,

2
Ho questo errore Errore CS0123 Nessun sovraccarico per 'UpdateDB' corrisponde al delegato 'ParameterizedThreadStart'
Omid Farvid

482

Uno dei 2 sovraccarichi del costruttore di thread accetta un delegato ParameterizedThreadStart che consente di passare un singolo parametro al metodo start. Sfortunatamente però consente solo un singolo parametro e lo fa in modo non sicuro perché lo passa come oggetto. Trovo che sia molto più facile usare un'espressione lambda per catturare i parametri rilevanti e passarli in modo fortemente tipizzato.

Prova quanto segue

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: Anche se la risposta attualmente selezionata è assolutamente corretta, questa di JaredPar è la migliore. È semplicemente la soluzione migliore per la maggior parte dei casi pratici.
galaktor,

2
Questa soluzione è molto meglio dello standrard ParameterizedThreadStart
Piotr Owsiak,

5
Bello così semplice. Basta avvolgere qualsiasi chiamata in "new Thread (() => FooBar ()) .Start ();
Thomas Jespersen,

12
Fantastico, questo è per i ragazzi di VB.NETDim thr As New Thread(Sub() DoStuff(settings))
dr. male

3
@bavaza Mi riferivo solo al controllo del tipo statico
JaredPar

141

Puoi usare le espressioni lambda

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

questa è finora la migliore risposta che ho trovato, è facile e veloce.


6
Migliore soluzione per casi semplici IMO
Dunc

1
cos'è =>? e dove posso trovare ulteriori informazioni sulla sintassi?
Nick,

2
Questa è un'espressione lambda, alcune informazioni sono disponibili su questi indirizzi: msdn.microsoft.com/en-us/library/vstudio/bb397687.aspx | codeproject.com/Articles/24255/Exploring-Lambda-Expression-in-C | dotnetperls.com/lambda
Georgi-it

1
Questo ha funzionato per me. Ho provato ParameterizedThreadStart e varianti di esso ma non ho avuto gioia. Stavo usando .NET Framework 4 in un'applicazione per console apparentemente semplice.
Daniel Hollinrake,

Funziona meglio per le persone che sono abituate a questo tipo di delegati. Potrebbe essere difficile per i principianti di udnerstand. Questo è pulito per gli standard C # però. La risposta accettata non funziona per me e non ho il tempo di scoprire perché.
Bitterblue,

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

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

Il tipo di parametro deve essere un oggetto.

MODIFICARE:

Sebbene questa risposta non sia errata, sconsiglio questo approccio. L'uso di un'espressione lambda è molto più facile da leggere e non richiede il cast di tipo. Vedi qui: https://stackoverflow.com/a/1195915/52551


Perché stai aiutando con un codice che non viene compilato;) Parameter?
Sebastian Xawery Wiśniowiecki il

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
Questo mi sta dando "Nessun sovraccarico per" DoWork "corrisponde al delegato" System.Threading.ParameterizedThreadStart "
anon58192932

1
Quale sarebbe la differenza se hai appena passato ThreadMethod nell'inizializzazione di Thread t?
Joe,

Ricorda, il tipo di parametro deve essere di tipo "Oggetto"
Kunal Uppal

28

Modo semplice usando lambda in questo modo ..

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

O potresti anche delegateusare ThreadStartcosì ...

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+ anche più pulito in questo modo ..

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



6

Come già menzionato in varie risposte qui, la Threadclasse attualmente (4.7.2) fornisce diversi costruttori e un Startmetodo con sovraccarichi.

Questi costruttori rilevanti per questa domanda sono:

public Thread(ThreadStart start);

e

public Thread(ParameterizedThreadStart start);

che può assumere un ThreadStartdelegato o un ParameterizedThreadStartdelegato.

I delegati corrispondenti si presentano così:

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

Come si può vedere, il costruttore corretto da utilizzare sembra essere quello che prende un ParameterizedThreadStartdelegato in modo che un thread conforme alla firma specificata del delegato possa essere avviato dal thread.

Un semplice esempio per istanziare la Threadclasse sarebbe

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

o solo

Thread thread = new Thread(Work);

La firma del metodo corrispondente (chiamato Workin questo esempio) è simile alla seguente:

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

Ciò che resta è iniziare il thread. Questo viene fatto usando uno dei due

public void Start();

o

public void Start(object parameter);

Mentre Start()avvia il thread e passa nullcome dati al metodo, Start(...)può essere utilizzato per passare qualsiasi cosa al Workmetodo del thread.

Esiste tuttavia un grosso problema con questo approccio: tutto ciò che viene passato nel Workmetodo viene inserito in un oggetto. Ciò significa che all'interno del Workmetodo deve essere nuovamente eseguito il cast nel tipo originale come nell'esempio seguente:

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



Il casting è qualcosa che di solito non vuoi fare.

Cosa succede se qualcuno passa qualcos'altro che non è una stringa? Dal momento che questo non sembra possibile all'inizio (poiché è il mio metodo, so cosa faccio o Il metodo è privato, come dovrebbe mai qualcuno essere in grado di passargli qualcosa? ), Potresti finire con quel caso per vari motivi . Poiché alcuni casi potrebbero non essere un problema, altri lo sono. In questi casi probabilmente finirai con una InvalidCastExceptioncosa che probabilmente non noterai perché termina semplicemente il thread.

Come soluzione ti aspetteresti di ottenere un ParameterizedThreadStartdelegato generico come ParameterizedThreadStart<T>dove Tsarebbe il tipo di dati che vuoi passare al Workmetodo. Purtroppo qualcosa del genere non esiste (ancora?).

Esiste tuttavia una soluzione suggerita a questo problema. Implica la creazione di una classe che contenga sia i dati da passare al thread sia il metodo che rappresenta il metodo worker in questo modo:

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 questo approccio inizieresti il ​​thread in questo modo:

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

thread.Start();

Quindi in questo modo eviti semplicemente di lanciarti e hai un modo semplice di fornire dati a un thread ;-)


Caspita, un voto negativo senza commenti ... O la mia risposta è negativa come il cast o il lettore non ha capito cosa ho cercato di sottolineare qui ;-)
Markus Safar

1
Ho trovato la tua soluzione molto illuminante, complimenti. Volevo solo aggiungere che ho già testato in Net.Core il seguente e ho lavorato senza dover esplicitare il cast! :-) private static void MyMethod<T>(T myData) { T message = myData; Console.WriteLine($"the thread wrote: {message}"); }
Paul Efford,

@PaulEfford Grazie ;-) La tua soluzione sembra piuttosto carina. Ma non hai accesso al tipo di informazioni specifiche in quanto verranno comunque inscatolate in un oggetto, giusto? (ad esempio message.Lengthnon è possibile e così via)
Markus Safar

1
giusto ... potresti message.GetType () e trasmettere se richiesto una proprietà specifica come if(myData.GetType() == typeof(string)) { var str = ((string)(object)myData).Length; }. Ad ogni modo, invece di utilizzare il metodo di threading ho trovato un po 'più comodo da usare Tasks<T>, come per esempio tasks.Add(Task.Run(() => Calculate(par1, par2, par3))), vedere la mia risposta qui sotto ( stackoverflow.com/a/59777250/7586301 )
Paul Efford

5

Ho riscontrato un problema con il parametro passato. Ho passato il numero intero da un ciclo for alla funzione e l'ho visualizzato, ma ha sempre dato risultati diversi. come (1,2,2,3) (1,2,3,3) (1,1,2,3) ecc. con delegato ParametrizedThreadStart .

questo semplice codice ha funzionato come un fascino

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

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

4

La ParameterizedThreadStartprende un parametro. Puoi usarlo per inviare un parametro o una classe personalizzata contenente diverse proprietà.

Un altro metodo consiste nel mettere il metodo che si desidera avviare come membro di istanza in una classe insieme alle proprietà per i parametri che si desidera impostare. Crea un'istanza della classe, imposta le proprietà e avvia il thread specificando l'istanza e il metodo e il metodo può accedere alle proprietà.


3

È possibile utilizzare un delegato 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

Propongo di utilizzare Task<T>invece di Thread; consente più parametri ed esegue davvero bene.

Ecco un esempio funzionante:

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

Il multithreading con thread C # ti consente di sviluppare applicazioni più efficienti sincronizzando attraverso la memoria condivisa.
Mohammed Hassen Ismaile
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.