2011-06-08 12 views
7

es nueva en WCF.Bloqueo del cliente WCF debido a una devolución de llamada incluso cuando la devolución de llamada IsOneWay

Tengo un cliente que está bloqueado cuando se llama a un servicio WCF.

El servicio invocará una devolución de llamada al cliente en el momento de la llamada marcada como IsOneWay. Confirmé que el servicio no está bloqueando en la devolución de llamada.

El cliente vuelve a llamar inmediatamente al mismo servicio (en un circuito cerrado), sin haber reparado la devolución de llamada. Luego, el cliente se bloquea (y un punto de interrupción en el lado del servicio nunca se activa).

Así que para recapitular:

CLIENT        SERVICE 
Call service -----------------------> (service breakpoint triggers) 
(waiting for dispatch thread) <------ Invoke callback (IsOneWay - doesn't block) 
             Service returns 

Call service again immediately -----? (service breakpoint doesn't trigger) 
(deadlock) 

Estoy asumiendo que la devolución de llamada ha agarrado un poco de bloqueo WCF en el extremo del cliente, y luego la segunda llamada de servicio por parte del cliente también quiere que la cerradura, por lo DeadLock resultados. Pero esto es solo una suposición.

He leído acerca de ConcurrencyMode pero no puedo decidir qué modo usar o dónde ubicarlo porque no tengo 100% claro qué está pasando y qué está bloqueado exactamente.

También preferiría mantener todas las devoluciones de llamadas a ser atendidas por el hilo de envío si es posible, ya que mantiene el código más simple.

¿Pueden los expertos de WCF arrojar luz sobre exactamente lo que está sucediendo aquí?

Muchas gracias

+0

¿Puede mostrarnos el código? –

+0

No vale la pena, no hay nada. Es más un problema para mí entender cómo WCF trata y sincroniza devoluciones de llamada. – GazTheDestroyer

+0

¿Qué tipo de aplicación de cliente tienes? ¿Son ambas llamadas de cliente y de devolución de llamada de una manera o es alguno de ellos con respuesta? –

Respuesta

20

Bien, creo que lo he sospechado.

servicios de WCF predeterminados a un solo subproceso. Todas las llamadas y devoluciones de llamadas se agrupan en un solo hilo (o SynchronizationContext para ser más preciso).

Mi aplicación es una aplicación WPF con una sola hebra, por lo que SynchronizationContext se establece en el hilo de envío.

Cuando entra la devolución de llamada, intenta coordinar la llamada a la cadena de distribución, que por supuesto está bloqueada en la llamada de servicio original. No estoy seguro de que se bloquee exactamente, pero obviamente hay algún bloqueo global que intenta obtener antes de esperar el hilo de envío.

Cuando el hilo de envío llama al servicio nuevamente, se bloquea en este bloqueo global.

dos formas de hacerlo:

1) crear el proxy de servicio en un subproceso diferente en el primer lugar. En su lugar, todas las llamadas serán coordinadas a través de este hilo y no importará que el hilo de envío esté bloqueado.

2) Aplicar [CallbackBehavior (UseSynchronizationContext = false)] atributo a la clase de cliente que implementa la devolución de llamada. Esto significa que WCF ignorará el contexto de sincronización cuando la devolución de llamada entra, y lo reparará en cualquier conversación disponible.

Fui con 2. Obviamente, esto significa que tengo que coordinar las devoluciones de llamadas que podrían actualizar la interfaz gráfica de usuario a la cadena de envío, pero afortunadamente mi implementación de devolución de llamada es una pequeña envoltura de todos modos, así que solo hago un _dispatcher.BeginInvoke() en cada método de devolución de llamada para ordenar ASÍNCRONAMENTE. El hilo de envío se servirá cuando tenga oportunidad, que es lo que quería en primer lugar.

+1

[CallbackBehavior (UseSynchronizationContext = false)] fue la respuesta en mi caso. He estado buscando una solución todo el día, y finalmente encontré esto. Gracias. – alexandrudicu

+0

Me alegro de que haya ayudado a alguien, ¡salud! – GazTheDestroyer

+1

Una tercera forma: puede establecer 'SynchronizationContext' en' InstanceContext' utilizado para crear 'DuplexChannelFactory'. Configurarlo en un simple 'nuevo SynchronizationContext()' funciona bien. –

0

La secuencia que ha representado asemeja a una llamada sincrónica. Mientras que en una llamada asincrónica, la secuencia sería:

Client       Server 
Call service --------------->ProcessRequest(1) //Your for loop for instance. 
Call service --------------->ProcessRequest(2) 
Call service --------------->ProcessRequest(3) 
Call service --------------->ProcessRequest(4) 
Call service --------------->ProcessRequest(5) 

Callback awake <---------------Response1 //Responses tends to pour in... 
Callback awake <---------------Response2 
Callback awake <---------------Response3 
Callback awake <---------------Response4... 

En cada caso de cada llamada de servicio asíncrono web, el sistema crea un hilo IO separado (hilo IOCP), y procesa la solicitud. En esto, pocas veces encontrarás un punto muerto.

He encontrado de esta manera, incluso cuando se llama dentro de un ciclo, que está funcionando muy bien.

Puede, por ejemplo, registrarse para el evento .OnProcessComplete, y luego llamar al método ProcessCompleteAsync.

+0

Aunque no quiero llamadas asíncronas. Esperaba que las devoluciones de llamada se pusieran en cola de manera similar a su diagrama, y ​​podría atenderlas en el hilo de envío cuando tuviera la oportunidad. Sin embargo, tengo la sensación de que esto no es posible. :/ – GazTheDestroyer

+0

Las devoluciones de llamada * son * llamadas asíncronas. Una devolución de llamada es cuando solicita notificaciones (eventos, por ejemplo); entonces usted es * notificado *, en la forma en que su método/función se devuelve. –

+0

Lo sentimos, las devoluciones de llamada obviamente son asincrónicas. Parecía haber deducido anteriormente que convierto las llamadas de servicio originales a asíncronas para que el hilo de envío sea gratuito. – GazTheDestroyer

Cuestiones relacionadas