2010-10-29 23 views
6

Estoy trabajando en una biblioteca de envoltura para un controlador de robot, que se basa principalmente en llamadas P/Invoke.Llamadas Async P/invocación

Sin embargo, gran parte de la funcionalidad del robot, como la localización o el movimiento, lleva bastante tiempo y se bloquea durante la ejecución.

Así que me pregunto cómo puedo ajustar la funcionalidad de manera asíncrona, por lo que las llamadas no bloquean mi subproceso de interfaz de usuario. Mi idea hasta ahora es usar Tareas, pero no estoy seguro de que sea el enfoque correcto.

public Task<bool> HomeAsync(Axis axis, CancellationToken token) 
{ 
    return Task.Factory.StartNew(() => Home(axis), token); 
} 

La mayoría de los artículos de MSDN sobre el modelo asíncrono en .NET a partir de ahora, la mayoría está retransmitiendo en bibliotecas ya tienen funcionalidad asíncrono (como File.BeginRead y así sucesivamente). Pero parece que no puedo encontrar mucha información sobre cómo escribir la funcionalidad asincrónica en primer lugar.

+0

¿Qué tipo de interfaz estás utilizando? ¿O es esta una biblioteca que tiene que ser compilada independientemente de una interfaz específica? –

+0

Suponiendo que te refieres a la interfaz de la interfaz de usuario, la construcción de la aplicación en la parte superior es WPF. Pero preferiría manejarlo a nivel de biblioteca, por lo que el equipo de UI no tiene que preocuparse demasiado por el uso de subprocesos. –

+1

La interfaz del robot normalmente no funciona de esta manera. Perderías completamente el control sobre el dispositivo, ni siquiera podrías abortar el movimiento de referencia. Un comando de inicio normalmente comienza el movimiento de inicio, luego sondear u obtener una señal cuando se completa. Compruebe lo que está disponible en la interfaz antes de comprometerse a hacerlo de esta manera. –

Respuesta

4

¿Alguna vez ha intentado async delegates? Yo creo que no hay nada más simple que eso.

Si su método de bloqueo de hilos es void Home(Axis), primero tiene que definir un tipo de delegado, es decir. delegate void HomeDelegate(Axis ax), luego use el método BeginInvoke de una nueva instancia de HomeDelegate que apunta a la dirección del método Home.

[DllImport[...]] //PInvoke 
void Home(Axis x); 

delegate void HomeDelegate(Axis x); 

void main() 
{ 
    HomeDelegate d = new HomeDelegate(Home); 
    IAsyncResult ia = d.BeginInvoke(axis, null, null); 
    [...] 
    d.EndInvoke(ia); 
} 

Por favor tener en cuenta que el uso de la EndInvoke en alguna parte (el bloqueo de la rosca hasta que el método ha terminado, tal vez junto con el sondeo de la propiedad IAsyncResult.Completed) es muy útil para comprobar si su tarea asíncrona ha sido realmente terminado. Puede que no quieras que tu robot abra su brazo y deje un vaso hasta que el vaso esté sobre la mesa, ya sabes ;-)

+1

Y ya no necesita definir tipos de delegados. Simplemente use 'Acción '. – erikkallen

+0

¡Sí, claro! Me olvidé de la Acción !! :-D –

+0

Creo que la Biblioteca paralela de tareas lo incluye todo en la clase Tarea, ¿no? –

1

Mi primera reacción es que esto no es algo que debas hacer en la biblioteca. La razón principal es que la forma en que implemente dicho sistema puede depender del tipo de interfaz que esté creando en la biblioteca.

Dicho esto, tiene básicamente dos opciones. Primero es el IAsyncResult. Una buena descripción de esto se puede encontrar en http://ondotnet.com/pub/a/dotnet/2003/02/24/asyncdelegates.html.

La segunda opción es crear comandos con eventos de devolución de llamada. El usuario crea una clase de comando y establece una devolución de llamada sobre eso. Luego, programe el comando en un ThreadPool y después de que se haya ejecutado el comando, plantee ese evento.

Las interfaces más antiguas de .NET Framework implementaron principalmente el enfoque IAsyncResult, donde las interfaces más nuevas tienden a implementar el enfoque de devolución de llamada por evento.

+0

¿Y poner en cola un artículo en un ThreadPool no bloquea el subproceso UI? Incluso si tengo eventos que indican cuándo se realiza una operación, es bastante inútil si tengo que envolver todas las llamadas en subprocesos de todos modos para evitar el bloqueo de la interfaz de usuario. –

+0

Ponerlo en cola al 'ThreadPool' no bloquea, no. La razón para usar una interfaz de devolución de llamada es que puede dejar la sincronización a la implementación de la interfaz de la interfaz de usuario. Simplemente proporciona una forma de indicarle a la UI que has terminado, y la interfaz de usuario lo toma desde allí. Otra ventaja es que las devoluciones de llamada son opcionales, por lo que cuando la UI no necesita notificación, simplemente no registra una devolución de llamada y simplemente se activa y se olvida. –

+0

Sí, pero el modelo de devolución de llamada también fue mi primera sugerencia. Supongo que la gente no está familiarizada con TPL. –

3

Después de una gran discusión, creo que algo así será el dorado medio.

public void HomeAsync(Axis axis, Action<bool> callback) 
{ 
    Task.Factory 
     .StartNew(() => Home(axis)) 
     .ContinueWith(task => callback(task.Result)); 
} 

Esto está usando lo mejor de ambos mundos, creo.