2009-12-21 14 views
5

Ho un programma che esegue un metodo attraverso un Thread.Start. Il metodo ha un valore di ritorno a cui mi piacerebbe avere accesso. C'è un modo per fare questo? Qui è un campione ...Accedi al valore restituito dalla funzione delegato di Thread.Start()

var someValue = ""; 
Thread t = new Thread(delegate() { someValue = someObj.methodCall(); }); 

t.Start(); 

while (t.isAlive) Thread.Sleep(1000); 

// Check the value of someValue 

Quindi una volta che le estremità ciclo, sarà il someValue dovrebbe essere impostato - ma perché è eseguito in un altro thread non venga impostato. C'è un modo semplice per accedervi?

+2

Hai provato a dichiarare alcunValore come "volatile"? –

+0

Anche se tale tecnica di sincronizzazione è piuttosto strana, dovrebbe funzionare con il modificatore volatile. +1 per Anon –

risposta

5

Quando il chiamante e il metodo threaded condividono una variabile, si ha già accesso ad essa - una volta che il thread è stato completato, è sufficiente controllare someValue.

Ovviamente, è necessario sapere quando il metodo thread è completo perché ciò sia utile. In fondo, ci sono due modi per farlo:

  • Invia un callback nel metodo filettato che può eseguire quando è finito. È possibile passare il metodo di richiamata someValue. È possibile utilizzare questa tecnica se non si cura quando viene eseguita la richiamata.

  • Utilizzare un WaitHandle di un tipo (o Thread.Join). Questi ti dicono quando una risorsa è pronta o un evento è stato completato. Questa tecnica è utile se vuoi iniziare una discussione, fare qualcos'altro, quindi attendere il completamento del thread prima di procedere. (In altre parole, è utile se si desidera sincronizzare il backup con il filo, proprio non subito.)

0

Date un'occhiata al Asynchronous Programming Model.

In uno degli schemi comuni descritti dal modello, la classe esporrà i metodi BeginXXX e EndXXX. Il primo avvia l'operazione asincrona e restituisce un oggetto IAsyncResult. Quest'ultimo accetta l'oggetto IAsyncResult come argomento, blocca il thread chiamante fino al completamento dell'operazione e restituisce il valore richiesto.

4

Non riesco a ricreare il problema, ho lo stesso codice e vedo il risultato previsto. Se stai per andare a dormire il thread corrente fino a quando non è completo, puoi semplicemente chiamare .Join() sul thread e attendere per assicurarti che sia stato eseguito.

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    string someValue = ""; 

    private void Form1_Load(object sender, EventArgs e) 
    { 

     Thread t = new Thread(delegate() { someValue = "asdf"; }); 

     t.Start(); 
     t.Join(); 

     //while (t.IsAlive) Thread.Sleep(1000); 

     System.Diagnostics.Debug.Print(someValue); 

    } 
} 
+0

L'ho dormito perché ho bisogno di guardare l'utente per cancellare e segnalare che il thread si ferma. – bugfixr

+4

Chu: Quello che stai descrivendo è uno scenario classico per un componente BackgroundWorker (se sei su Windows Form). È molto meglio che dormire il thread dell'interfaccia utente per un secondo alla volta. – itowlson

+0

+1 per BackgroundWorker. Ha metodi integrati per mostrare l'avanzamento dell'esecuzione e annullare l'attività, per non parlare del fatto che non bloccherà il thread dell'interfaccia utente mentre è in esecuzione. Se l'utente preme un pulsante Annulla sul thread dell'interfaccia utente, è possibile impostare il flag sul backgroundworker e quindi controllare la proprietà CancellationPending per sapere quando saltare fuori dal task asincrono. –

1

Uno dei possibili metodi per restituire un valore da un thread consiste nell'utilizzare una classe di contesto come oggetto parametro. Può essere usato per passare i parametri e recuperare il risultato.

Se invece è possibile utilizzare una classe BackgroundWorker, ha già un oggetto Result dedicato, che funziona allo stesso modo. Ma BackgroundWorker non può essere utilizzato per alcuni scopi (ad esempio, non supporta STA Apartment State).

Ricordare che non è necessario leggere da ctx.Result finché il thread non è terminato (cioè t.IsAlive == false).

void runThread()   
    { 
     ThreadContext ctx = new ThreadContext(); 
     ctx.Value = 8; 

     Thread t = new Thread(new ParameterizedThreadStart(MyThread)); 
     //t.SetApartmentState(ApartmentState.STA); // required for some purposes 
     t.Start(ctx); 

     // ... 
     t.Join(); 

     Console.WriteLine(ctx.Result); 
    } 

    private static void MyThread(object threadParam) 
    { 
     ThreadContext context = (ThreadContext)threadParam; 

     context.Result = context.Value * 4; // compute result 
    } 

    class ThreadContext 
    { 
     public int Value { get; set; } 
     public int Result { get; set; } 
    } 
0

È possibile recuperare i dati dalla funzione Thread utilizzando la funzione di chiamata delegata. Il delegato può fungere da ponte tra thread e il chiamante. Ad esempio:

public delegate void DelReturnValue(string value); 
public class SayHello 
{ 
    private string _name; 
    private DelReturnValue _delReturnValue; 

    public SayHello(string name, DelReturnValue delReturnValue) 
    { 
     _name = name; 
     _delReturnValue = delReturnValue; 
    } 

    public void SayHelloMethod() 
    { 
     _delReturnValue(_name); 
    } 
} 

public class Caller 
{ 
    private static string _returnedValue; 
    public static void ReturnValue(string value) 
    { 
     _returnedValue = value; 
    } 

    public static void Main() 
    { 
     DelReturnValue delReturnValue=new DelReturnValue(ReturnValue); 
     SayHello sayHello = new SayHello("test", delReturnValue); 
     Thread newThread = new Thread(new ThreadStart(sayHello.SayHelloMethod)); 
     newThread.Start(); 
     Thread.Sleep(1000); 
     Console.WriteLine("value is returned: " + _returnedValue); 
    } 
} 
Problemi correlati