2009-12-05 11 views
20

He pasado por this SO question pero no ayudó.InvalidOperationException - objeto actualmente está en uso en otro lugar

El caso aquí es diferente. Estoy usando Backgroundworkers. BackgroundWorker primero comienza a funcionar en la entrada de la imagen del usuario y en el interior firstbackgroundworker_runworkercompleted() Estoy usando llamar 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 hacen en otra algo * backgrougrondworker_doWork().

Ahora A VECES Recibo "InvalidOperationException - objeto actualmente está siendo utilizado en otro lugar". Es muy arbitrario. A veces obtengo esto en algo1backgroundworker_DoWork y algunas veces en algo2backgroundworker_DoWork y algunas veces en Application.Run (new myWindowsForm());

No tengo ni idea de qué está pasando.

Respuesta

39

Hay un bloqueo dentro de GDI + que impide que dos subprocesos accedan a un mapa de bits al mismo tiempo. Este no es un tipo de bloqueo de bloqueo, es un tipo de bloqueo "el programador hizo algo mal, yo lanzaré una excepción". Tus hilos están bombardeando porque estás clonando la imagen (== accediendo a un mapa de bits) en todos los hilos. Su hilo de interfaz de usuario está bombardeando porque está tratando de dibujar el mapa de bits (== accediendo a un mapa de bits) al mismo tiempo que un hilo lo está clonando.

Deberá restringir el acceso al mapa de bits a solo un hilo. Clone las imágenes en el subproceso de la interfaz de usuario antes de iniciar el BGW, cada BGW necesita su propia copia de la imagen. Actualice la propiedad Imagen de PB en el evento RunWorkerCompleted.Perderá algo de concurrencia de esta manera, pero eso es inevitable.

19

Parece que sus BackgroundWorkers están intentando acceder a los mismos componentes de Windows Forms al mismo tiempo. Esto explicaría por qué la falla es aleatoria.

Tendrá que asegurarse de que esto no sucede por el uso de un lock, quizá de este modo:

 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 es local en este método - que sin duda no lo hace ¡quiero compartirlo en todos los métodos!

Por otro lado, todos los métodos usan la misma instancia de lockObject. Cuando un método BackgroundWorker ingresa a su sección lock{}, se bloquearán otros que lleguen a ese punto. Por lo tanto, 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 para asegurarse de no realizar una actualización cruzada de la interfaz de usuario. Compruebe this post para una buena manera de evitar eso.

1

En los formularios de Windows, no solo debe acceder a los controles desde un único subproceso, sino que dicho subproceso debe ser el subproceso principal de la aplicación, el subproceso que creó el control.

Esto significa que en DoWork no debe acceder a ningún control (sin utilizar Control.Invocar). Entonces aquí llamarías a RunWorkerAsync pasando tu clon de imagen. Dentro del controlador de eventos DoWork, puede extraer el parámetro del DoWorkEventArgs.Argument.

Solo los controladores de eventos ProgressChanged y RunWorkerCompleted deben interactuar con la GUI.

Cuestiones relacionadas