5

Dejemos de lado, por el momento, el question de si las operaciones sincrónicas deberían incluso intentarse dentro del contexto de una aplicación Silverlight. Si uso ManualResetEvent como en el siguiente código:¿Por qué ManualResetEvent no funciona en esta llamada síncrona usando Silverlight 4?

static string result; 
    static AutoResetEvent are = new AutoResetEvent(false); 
    static ManualResetEvent mre = new ManualResetEvent(false); 
    public static string AsyncCall() 
    { 
     string url = "https://stackoverflow.com/feeds/tag/silverlight"; 
     WebClient w = new WebClient(); 
     w.DownloadStringCompleted += new DownloadStringCompletedEventHandler(w_DownloadStringCompleted); 
     w.DownloadStringAsync(new Uri(url), url); 
     mre.WaitOne(); 
     return result; 
    } 

    static void w_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) 
    { 
     result = e.Result; 
     mre.Set(); 
    } 

Como era de esperar de la lectura de ManualResetEvent on MSDN, "Cuando el subproceso de control completa la actividad, se llama al método Set para señalar que los hilos de espera pueden proceder." , cuando se llama a Set() en w_DownloadStringCompleted, el control vuelve al hilo en espera que comenzó a esperar en AsyncCall. Esto es lo que sucede cuando se ejecuta esto con .NET 4.0. El hilo en AsyncCall se bloquea hasta que se completa la descarga y se llama a Set.

Si ejecuto el mismo código en Silverlight 4, se llamará a DownloadStringAsync, pero el control nunca alcanzará la devolución de llamada w_DownloadStringCompleted. Una vez que se llama a WaitOne(), ese hilo en AsyncCall simplemente se cuelga allí, y el hilo que despegó para procesar DownloadStringAsync nunca alcanza la devolución de llamada. La única forma en que he visto un hilo llegar a la devolución de llamada de descarga en SL4 es si el hilo de AsyncCall vuelve de AsyncCall. Entonces Set() nunca recibe una llamada.

¿Por qué ManualResetEvent no funciona como se esperaba en Silverlight 4? ¿Por qué difiere de .NET 4? ¿Es esto quizás la aplicación de Microsoft del patrón de diseño asincrónico? ¿O hay algo que me falta?

Gracias

+0

¿Qué ves en el depurador? – SLaks

+0

Si presiono Romper todo, veo que el depurador está bloqueado en WaitOne() y que solo hay un hilo en Subprocesos. –

Respuesta

3

Las devoluciones de llamada de red en Silverlight que siempre llegará en el mismo hilo a medida que se originaron. Por ejemplo, si crea un WebClient.DownloadStringAsync en el subproceso de la interfaz de usuario (es decir, en un evento de clic de botón), la llamada de devolución de llamada se pondrá en cola para entregarse en el mismo subproceso de interfaz de usuario. Sin embargo, su llamada al mre.WaitOne() está bloqueando el hilo de la interfaz de usuario, por lo que nunca se invoca la devolución de llamada, y la llamada mre.Set() nunca ocurre.

Así que sí, eso es un tipo de aplicación en la asincronicidad de las llamadas en red: realmente no puede hacer llamadas sincrónicas, incluso si parecen ser sincrónicas.

+0

¿Quiere decir que no puede hacer llamadas sincrónicas en el hilo principal de la interfaz de usuario? Porque recientemente descubrí cómo puedo hacer una llamada síncrona si se realiza en un hilo diferente. Sin embargo, en todos los casos parece que una llamada ManualResetEvent.Wait() realizada en el hilo de la interfaz de usuario principal bloqueará todas las llamadas de red asíncronas, incluso si se crearon en un subproceso diferente. –

+1

Correcto, usted realmente, realmente, realmente no puede hacer llamadas de sincronización en el hilo de la interfaz de usuario. Eso esencialmente provocaría que la aplicación se "cuelgue", que es exactamente el motivo de la decisión de no permitir las llamadas de sincronización. – carlosfigueira

+0

+1 por el énfasis adicional de que realmente, realmente, realmente no puedes hacer llamadas de sincronización. –

Cuestiones relacionadas