varios tiempo programacion procesos otro multihilo mismo hilos formulario ejecutar acceder c# wpf multithreading task-parallel-library blocking

c# - tiempo - Ejecutando un control WPF en otro hilo



hilos de procesos c# (2)

Bueno, tengo un método que funciona, pero puede que no sea el más elegante.

Tengo una ventana que contiene mi control de terceros (representación lenta) en el XAML.

public partial class MapWindow : Window { private ConcurrentQueue<MapCommand> _mapCommandQueue; private HwndSource _source; // ... }

Mi hilo principal (UI) construye e inicia esta ventana en un hilo:

_leftTopThread = new Thread(() => { _topLeftMap = new MapWindow() { WindowStartupLocation = WindowStartupLocation.Manual, CommandQueue = _leftMapCommendQueue, }; _topLeftMap.Show(); System.Windows.Threading.Dispatcher.Run(); }); _leftTopThread.SetApartmentState(ApartmentState.STA); _leftTopThread.IsBackground = true; _leftTopThread.Name = "LeftTop"; _leftTopThread.Start();

Luego obtengo un identificador de la ventana en el hilo (después de que se haya inicializado):

private IntPtr LeftHandMapWindowHandle { get { if (_leftHandMapWindowHandle == IntPtr.Zero) { if (!_topLeftMap.Dispatcher.CheckAccess()) { _leftHandMapWindowHandle = (IntPtr)_topLeftMap.Dispatcher.Invoke( new Func<IntPtr>(() => new WindowInteropHelper(_topLeftMap).Handle) ); } else { _leftHandMapWindowHandle = new WindowInteropHelper(_topLeftMap).Handle; } } return _leftHandMapWindowHandle; } }

... y después de colocar un comando en la cola segura para subprocesos que se comparte con la ventana de subprocesos:

var command = new MapCommand(MapCommand.CommandType.AircraftLocation, new object[] {RandomLatLon}); _leftMapCommendQueue.Enqueue(command);

.. Hago saber que puede revisar la cola:

PostMessage(LeftHandMapWindowHandle, MapWindow.WmCustomCheckForCommandsInQueue, IntPtr.Zero, IntPtr.Zero);

La ventana puede recibir mi mensaje porque se ha enganchado en los mensajes de la ventana:

protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); _source = PresentationSource.FromVisual(this) as HwndSource; if (_source != null) _source.AddHook(WndProc); }

..que entonces puede comprobar:

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) // { // Handle messages... var result = IntPtr.Zero; switch (msg) { case WmCustomCheckForCommandsInQueue: CheckForNewTasks(); break; } return result; }

..y luego ejecute en el hilo!

private void CheckForNewTasks() { MapCommand newCommand; while (_mapCommandQueue.TryDequeue(out newCommand)) { switch (newCommand.Type) { case MapCommand.CommandType.AircraftLocation: SetAircraftLocation((LatLon)newCommand.Arguments[0]); break; default: Console.WriteLine(String.Format("Unknown command ''0x{0}''for window", newCommand.Type)); break; } } }

Tan fácil como eso ... :)

Estoy usando un control visual en mi proyecto que proviene de una biblioteca a la que no tengo la fuente.
Se tarda demasiado en actualizar (200 ms, aproximadamente) para obtener una buena capacidad de respuesta de la interfaz de usuario con tres de estos controles en pantalla al mismo tiempo. (Es posible que deba actualizar los tres a la vez, lo que deja mi UI bloqueada durante unos 600 ms mientras todos están pensando).

He leído algunas publicaciones sobre TaskSchedulers y estoy comenzando a investigar las funciones de la tarea Paralela como una forma de ejecutar cada uno de estos controles en su propio hilo. La plataforma será multi-core, por lo que quiero aprovechar el procesamiento simultáneo.

Sin embargo, el problema es que ni siquiera sé lo que no sé sobre cómo hacerlo.

¿Existe un patrón de diseño adecuado para ejecutar un control en un subproceso separado del subproceso de la interfaz de usuario principal en WPF?

Específicamente : es un control de mapa de terceros, que cuando se le asigna una nueva ubicación o nivel de zoom tarda demasiado tiempo en volver a dibujar (~ 200 ms). Con quizás tres de estas actualizaciones a un máximo de 4Hz, obviamente no se mantendrán al día.
He encapsulado el control WPF en un control de usuario, y necesito ejecutar cada instancia en su propio hilo, mientras capturo las entradas del usuario (clics del mouse, por ejemplo).

ACTUALIZACIÓN : mientras estoy buscando una solución, he implementado lo siguiente hasta ahora.
Mi hilo principal (UI) genera un hilo que crea una nueva ventana que contiene el control en cuestión y lo ubica en la posición correcta (para que parezca que es solo un control normal).

_leftTopThread = new Thread(() => { _topLeftMap = new MapWindow() { WindowStartupLocation = WindowStartupLocation.Manual, Width = leftLocation.Width, Height = leftLocation.Height, Left = leftLocation.X, Top = leftLocation.Y, CommandQueue = _leftMapCommandQueue, }; _topLeftMap.Show(); System.Windows.Threading.Dispatcher.Run(); }); _leftTopThread.SetApartmentState(ApartmentState.STA); _leftTopThread.IsBackground = true; _leftTopThread.Name = "LeftTop"; _leftTopThread.Start();

Donde CommandQueue es una cola de CommandQueue de bloqueo segura para subprocesos para enviar comandos al mapa (mover la ubicación, etc.).
El problema es que ahora puedo

  • tiene entrada de usuario debido a la llamada a System.Windows.Threading.Dispatcher.Run()
  • o bloque en el CommandQueue, escuchando los comandos enviados por el hilo principal

¡No puedo girar esperando los comandos, porque absorbería toda la CPU de mi hilo!
¿Es posible bloquear y hacer que el evento mensaje-bomba funcione?


He estado investigando esto también, y la información más relevante que pude encontrar estaba en esta publicación del blog (sin embargo, todavía no la he probado):

http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx

crea un HostVisual en el subproceso de la interfaz de usuario, luego gira un subproceso en segundo plano, crea un MediaElement, lo coloca dentro de un VisualTarget (que apunta al HostVisual), y lo pone todo dentro de nuestro hacky VisualTargetPresentationSource.

El problema con este método es que aparentemente el usuario no podrá interactuar con los controles que se ejecutan en el nuevo hilo.