c# - progressbar - runworkerasync
InvalidOperationException: el objeto está actualmente en uso en otro lugar (3)
He pasado por esta pregunta, pero no sirvió de nada.
El caso aquí es diferente. Estoy usando Backgroundworkers. 1er backgroundworker comienza a operar en la entrada de imagen del usuario y dentro de firstbackgroundworker_runworkercompleted () Estoy usando llamando a otros 3 backgroundworkers
algo1backgroundworker.RunWorkerAsync();
algo2backgroundworker.RunWorkerAsync();
algo3backgroundworker.RunWorkerAsync();
Este es el código para cada uno:
algo1backgroundworker_DoWork()
{
Image img = this.picturebox.Image;
imgclone = img.clone();
//operate on imgclone and output it
}
algo2backgroundworker_DoWork()
{
Image img = this.picturebox.Image;
imgclone = img.clone();
//operate on imgclone and output it
}
operaciones similares se realizan en otros algo * backgrougrondworker_doWork ().
Ahora, a VECES, obtengo "InvalidOperationException: el objeto está actualmente en uso en otro lugar". Es muy arbitrario. Algunas veces obtengo esto en algo1backgroundworker_DoWork y, a veces, en algo2backgroundworker_DoWork y, a veces, en Application.Run (new myWindowsForm ());
No tengo ni idea de lo que está pasando.
En los formularios de Windows, no solo debe acceder a los controles desde un solo hilo, sino que ese hilo debe ser el hilo principal de la aplicación, el hilo que creó el control.
Esto significa que en DoWork no debe acceder a ningún control (sin usar Control.Invoke). Así que aquí llamaría a RunWorkerAsync pasando su clon de imagen. Dentro del controlador de eventos DoWork, puede extraer el parámetro de DoWorkEventArgs.Argument.
Solo los controladores de eventos ProgressChanged y RunWorkerCompleted deben interactuar con la GUI.
Entonces, parece que sus BackgroundWorkers intentan acceder a los mismos componentes de Windows Forms al mismo tiempo. Esto explicaría por qué el fallo es aleatorio.
Deberá asegurarse de que esto no suceda utilizando un lock
, tal vez así:
private object lockObject = new object();
algo1backgroundworker_DoWork()
{
Image imgclone;
lock (lockObject)
{
Image img = this.picturebox.Image;
imgclone = img.clone();
}
//operate on imgclone and output it
}
Tenga en cuenta que me aseguro de que imgclone sea local a este método, ¡definitivamente no quiere compartirlo con todos los métodos!
Por otro lado, todos los métodos utilizan la misma instancia de lockObject. Cuando un método BackgroundWorker ingresa a su sección de lock{}
, se lock{}
otros que lleguen a ese punto. Por eso es importante asegurarse de que el código en la sección bloqueada sea rápido.
Cuando llegue a "generar" su imagen procesada, tenga cuidado también de asegurarse de no realizar una actualización de subprocesos en la interfaz de usuario. Revisa esta publicación para una manera limpia de evitar eso.
Hay un bloqueo dentro de GDI + que evita que dos subprocesos accedan a un mapa de bits al mismo tiempo. Este no es un bloqueo tipo bloqueo, es un "programador hizo algo mal, lanzaré una excepción" tipo de bloqueo. Sus subprocesos están bombardeando porque está clonando la imagen (== accediendo a un mapa de bits) en todos los subprocesos. Su hilo de interfaz de usuario está bombardeando porque está intentando dibujar el mapa de bits (== accediendo a un mapa de bits) al mismo tiempo que un hilo lo está clonando.
Tendrá que restringir el acceso al mapa de bits a un solo hilo. Clone las imágenes en el hilo de la interfaz de usuario antes de iniciar los BGW, cada BGW necesita su propia copia de la imagen. Actualice la propiedad de la imagen de PB en el evento RunWorkerCompleted. Perderás algo de concurrencia de esta manera pero eso es inevitable.