2011-09-02 10 views
12

Quiero hacer algo como lo siguiente: básicamente estoy llamando a una operación asíncrona que llamará a una devolución de llamada en otro hilo y quiero esperar a que se complete "en línea". Mi preocupación es que eso cambia las variables compartidas a través de subprocesos (barra & evento) puede no sincronizarse debido a que se almacena en los registros, por ejemplo. Si fueran variables miembro, podría marcarlos como volátiles pero volátiles no se pueden usar en variables locales creadas en la pila. Podría usar las variables miembro, pero creo que es más limpio y no desordena mi clase manteniéndolo todo local.¿Es seguro compartir la variable local entre subprocesos (a través de un cierre de devolución de llamada)?

Bar bar = null; 
ManualResetEvent event = new ManualResetEvent(false); 

foo.AsyncOperation(new Action(()=>{  
    // This delegate will be called in another thread 
    bar = ... 
    event.Set(); 
})); 

event.WaitOne(timeout); 
// use bar 
+2

Nota: a menos que haga algo más entre '' AsyncOperation' y WaitOne', que también podría ejecutarlo de forma sincrónica –

+0

Esta pregunta se relaciona: http://stackoverflow.com/questions/6581848/memory-barrier- generators/6932271 # 6932271 –

+0

@Marc - Buen punto, pero el API que estoy llamando inherentemente asíncrono. Se basa en mensajes enviados a través de la red a un servidor. Dentro de AsyncOperaton, se establece un mensaje y se notifica la devolución de llamada cuando hay una respuesta. Lo uso de forma asíncrona la mayor parte del tiempo, pero en este caso particular quiero esperar al resultado. Incluyo un tiempo de espera en WaitOne en caso de que la respuesta no llegue. – Shane

Respuesta

6

Sí, funcionará correctamente. Lea aquí

http://www.albahari.com/threading/part4.aspx

The following implicitly generate full fences:Setting and waiting on a signaling construct

y en la señalización construye el ManualResetEvent está incluido.

Si usted quiere saber lo que es un full fence Es decir, en la misma página:

completa vallas El tipo más simple de barrera de la memoria es una memoria llena barrera (valla completo) que impide cualquier tipo de instrucción de reordenamiento o cacheando alrededor de esa cerca. Calling Thread.MemoryBarrier genera una valla completa ;

+0

Cool; si el 'WaitOne' actúa como una valla, es seguro. Sí, sin embargo, con eso MSDN documentaría este http://msdn.microsoft.com/en-us/library/58195swd.aspx –

+2

@Marc. La documentación de msdn sobre seguridad y vallas de hilo es bastante deficiente, si no recuerdo mal, PERO http://msdn.microsoft.com/en-us/library/ms686355(v=vs.85).aspx 'Las siguientes funciones de sincronización utilizan las barreras adecuadas para garantizar el orden de la memoria:' 'Wait functions' and' Functions that objetos de sincronización de señal' – xanatos

+0

ordenados, entonces; Eliminaré mi respuesta –

4

Creo que su código funcionará - el cierre levantará luego en el montón, incluso si se acaba la pila de variables (el ManualReseetEvent seguramente no será).

Pero ¿por qué no pone todo después del evento.WaitOne() solo dentro de la continuación (el bloque fue el evento. Se llama al conjunto)? Creo que esta debería ser la forma preferida de manejar este tipo de situaciones y no te meterás en problemas de esta manera (no necesitas nada el Bar en el bloque externo, y aún puedes usar el MRE para verificarlo).

Consideraría convertir esto en Operaciones utilizando objetos Tarea - esto resolvería todo esto de una vez (por ejemplo, devolver una Tarea desde su AsyncOperation). A continuación, puede esperar el resultado de la Tarea y utilizar la barra de regresar ...

class Foo 
{ 
// ... 
private Task<Bar> AsyncOperation(Task<Bar> initializeBar) 
{ 
    return initializeBar 
      .ContinueWith(
      bar => { 
        /* do your work with bar and return some new or same bar */ 
        return bar; 
        }); 
} 
} 

y utilizar de esta manera:

var task = foo.AsyncOperation(Taks.Factory.StartNew(() => { /* create and return a bar */ })); 
var theBar = task.Result; // <- this will wait for the task to finish 
// use your bar 

PS: El cierre será básicamente envolverlos simplemente en una clase -objeto;) PPS: es difícil para mí probar este código sin su AsyncOperation pero debería funcionar con errores de sintaxis del módulo por ortografía/tipeo incorrectos.

+0

No estoy tan seguro, ¿cómo está * garantizado * para funcionar? las reglas usuales de datos/pedidos solo se aplican cuando un único hilo ... –

+0

obviamente usted sabe mucho más sobre esas cosas que yo, la pregunta era si este código se coloca en algún tipo de registro (y supuse) para ser reutilizado/recreado en el otro hilo) y creo que * esto * seguramente no sucederá. Y creo que vi algo muy similar en las cosas asincrónicas que F # usa y honestamente: he usado cosas similares (usando los eventos ManualResetEvents, definidos localmente para sincronizar los hilos), me tranquilizo mucho y nunca me meto en problemas. Pero no soy concurez, Wizzard. ¿Quizás puedas señalar dónde está el problema exactamente en lugar de insinuarlo? (sin ofensas - realmente interesado) – Carsten

+0

oh espera - usted (por supuesto) está pensando en el Bar - objeto, supongo ... hmm - que de hecho podría significar problemas ... – Carsten

Cuestiones relacionadas