2009-12-21 11 views
5

Tengo un programa que ejecuta un método a través de un Thread.Start. El método tiene un valor de retorno al que me gustaría tener acceso. ¿Hay alguna forma de hacer esto? He aquí una muestra ...Acceso a valor de retorno desde la función de delegado 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 

Así que una vez que los extremos bucle while, el someValue debe fijarse - sino porque es ejecutado en otro hilo no quede ajustado. ¿Hay una manera simple de acceder a ella?

+2

¿Ha intentado declarar algunosValores como 'volátiles'? –

+0

Aunque tal técnica de sincronización es bastante extraña, debería funcionar con un modificador volátil. +1 para Anon –

Respuesta

5

Cuando la persona que llama y el método enhebrado comparten una variable, usted ya tiene acceso a ella; una vez que el hilo se ha completado, simplemente marque someValue.

Por supuesto, debe saber cuándo se completa el método de roscado para que esto sea útil. En la parte inferior, hay dos maneras de hacer esto:

  • Enviar una devolución de llamada en el método de roscado que puede ejecutar cuando esté terminado. Puede pasar su método de devolución de llamada someValue. Puede utilizar esta técnica si no le importa cuándo se ejecuta la devolución de llamada.

  • Utilice un WaitHandle de algún tipo (o Thread.Join). Estos le indican cuándo un recurso está listo o si un evento se completó. Esta técnica es útil si desea iniciar un hilo, hacer otra cosa, y luego espere hasta que el hilo se complete antes de continuar. (En otras palabras, es útil si desea sincronizar de nuevo con el hilo, pero no de inmediato.)

0

Tener un vistazo a la Asynchronous Programming Model.

En uno de los patrones comunes que describe el modelo, su clase expondrá los métodos BeginXXX y EndXXX. El primero inicia la operación asincrónica y devuelve un objeto IAsyncResult. Este último acepta el objeto IAsyncResult como un argumento, bloquea el hilo de llamada hasta que se complete la operación y devuelve el valor requerido.

4

No puedo recrear su problema, tengo el mismo código y estoy viendo el resultado esperado. Si va a suspender el hilo actual hasta que esté completo, simplemente puede llamar a .Join() en el hilo y esperar para asegurarse de que se haya ejecutado.

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

Duermo porque necesito ver si el usuario cancela y señalo que el hilo se detenga. – bugfixr

+4

Chu: Lo que está describiendo es un escenario clásico para un componente de BackgroundWorker (si está en Windows Forms). Eso es mucho mejor que dormir el hilo de UI por un segundo a la vez. – itowlson

+0

+1 para BackgroundWorker. Tiene métodos integrados para mostrar el progreso de la ejecución y cancelar la tarea, sin mencionar que no bloqueará el subproceso de la interfaz de usuario mientras se está ejecutando. Si el usuario pulsa un botón de cancelar en el hilo de UI, puede establecer el indicador en backgroundworker y luego verificar la propiedad CancellationPending para saber cuándo salta de su tarea asíncrona. –

1

Uno de los posibles métodos para devolver un valor de un hilo es el uso de una clase de contexto como un objeto de parámetro. Se puede usar para pasar parámetros y recuperar el resultado también.

Si, por otro lado, puede utilizar una clase BackgroundWorker, ya tiene un objeto Result específico, que funciona de la misma manera. Pero BackgroundWorker no se puede usar para algunos fines (por ejemplo, no es compatible con STA Apartment State).

Tenga en cuenta que no debe leer desde ctx.Result hasta que finalice el subproceso (es decir, 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

Puede recuperar los datos de la función Subproceso utilizando delegate callback. El delegado puede servir como un puente entre el hilo y la persona que llama. Por ejemplo:

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); 
    } 
} 
Cuestiones relacionadas