2009-12-05 7 views
20

Ho attraversato this SO question ma non è stato di aiuto.InvalidOperationException - l'oggetto è attualmente in uso altrove

Il caso qui è diverso. Sto usando Backgroundworkers. 1 ° BackgroundWorker inizia opera sull'input immagine di utente e all'interno firstbackgroundworker_runworkercompleted() sto usando chiamando altri 3 backgroundworkers

algo1backgroundworker.RunWorkerAsync(); 
algo2backgroundworker.RunWorkerAsync(); 
algo3backgroundworker.RunWorkerAsync(); 

questo è il codice per ogni:

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 
} 

operazioni simili sono fatte in altri algo * backgrougrondworker_doWork().

Ora QUALCHE VOLTA ho trovato "InvalidOperationException - l'oggetto è attualmente in uso altrove". È molto arbitrario. A volte mi capita di trovarlo in algo1backgroundworker_DoWork ea volte in algo2backgroundworker_DoWork ea volte in Application.Run (new myWindowsForm());

Non ho idea di cosa sta succedendo.

risposta

39

C'è un blocco all'interno di GDI + che impedisce a due thread di accedere a una bitmap allo stesso tempo. Questo non è un tipo di blocco di blocco, è un "programmatore ha fatto qualcosa di sbagliato, io lancerò un'eccezione" tipo di blocco. I tuoi thread stanno bombardando perché stai clonando l'immagine (== accedendo a una bitmap) in tutti i thread. Il tuo thread UI sta bombardando perché sta tentando di disegnare la bitmap (== accedendo a una bitmap) nello stesso momento in cui un thread la sta clonando.

È necessario limitare l'accesso alla bitmap a un solo thread. Clona le immagini nel thread UI prima di avviare i BGW, ogni BGW ha bisogno della propria copia dell'immagine. Aggiorna la proprietà Image di PB nell'evento RunWorkerCompleted.Perderai un po 'di concorrenza in questo modo ma è inevitabile.

19

Quindi sembra che i tuoi Background Worker stiano cercando di accedere agli stessi componenti di Windows Form allo stesso tempo. Questo spiegherebbe perché l'errore è casuale.

Avrai bisogno di assicurarsi che questo non avviene utilizzando un lock, forse in questo 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 
    } 

noti che mi assicuro che è locale imgclone a questo metodo - sicuramente non si voglio condividerlo con tutti i metodi!

D'altra parte la stessa istanza di lockObject viene utilizzata da tutti i metodi. Quando un metodo BackgroundWorker entra nella sua sezione lock{}, gli altri che arrivano a quel punto verranno bloccati. Quindi è importante assicurarsi che il codice nella sezione bloccata sia veloce.

Quando si arriva a "stampare" l'immagine elaborata, fare attenzione anche per assicurarsi di non eseguire un aggiornamento cross-thread sull'interfaccia utente. Controlla this post per un modo semplice per evitarlo.

1

Nei moduli di Windows, non solo si devono accedere solo ai controlli da un singolo thread ma quello thread deve essere il thread dell'applicazione principale, il thread che ha creato il controllo.

Ciò significa che in DoWork non è necessario accedere a nessun controllo (senza utilizzare Control.Invoke). Quindi qui chiameresti RunWorkerAsync passando nel clone dell'immagine. All'interno del gestore di eventi DoWork, è possibile estrarre il parametro da DoWorkEventArgs.Argument.

Solo i gestori di eventi ProgressChanged e RunWorkerCompleted devono interagire con la GUI.

Problemi correlati