Подтвердить что ты не робот

InvalidOperationException - объект в настоящее время используется в другом месте

Я прошел этот вопрос SO, но это не помогло.

Случай здесь другой. Я использую Backgroundworkers. 1-й фоновой рабочий начинает работать на входе пользователя и внутри firstbackgroundworker_runworkercompleted() Я использую вызов 3 других фоновых работ

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

это код для каждого:

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
}

аналогичные операции выполняются в другом algo * backgrougrondworker_doWork().

Теперь ИТОГО Я получаю объект InvalidOperationException, который в настоящее время используется в другом месте. Это очень произвольно. Я иногда получаю это в algo1backgroundworker_DoWork, а иногда и в algo2backgroundworker_DoWork, а иногда и в Application.Run(new myWindowsForm());

Я не знаю, что происходит.

4b9b3361

Ответ 1

Внутри GDI + есть блокировка, которая предотвращает одновременное обращение двух потоков к растровому изображению. Это не блокирующий вид блокировки, это "программист сделал что-то не так, я выброшу исключение" вроде блокировки. Ваши потоки бомбардируются, потому что вы клонируете изображение (== доступ к растровому изображению) во всех потоках. Ваш поток пользовательского интерфейса бомбит, потому что он пытается рисовать растровое изображение (== доступ к растровому изображению), в то время как поток клонирует его.

Вам нужно ограничить доступ к растровому изображению только одним потоком. Клонирование изображений в потоке пользовательского интерфейса, прежде чем запускать BGW, каждый BGW нуждается в собственной копии изображения. Обновите свойство PB Image в событии RunWorkerCompleted. Вы потеряете concurrency таким образом, но это неизбежно.

Ответ 2

Итак, похоже, что ваши BackgroundWorkers пытаются одновременно получить доступ к тем же компонентам Windows Forms. Это объясняет, почему неудача является случайной.

Вам нужно убедиться, что этого не происходит, используя lock, возможно, так:

     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
     }

Обратите внимание, что я уверен, что imgclone является локальным для этого метода - вы определенно не хотите делиться им по всем методам!

С другой стороны, тот же экземпляр lockObject используется всеми методами. Когда метод BackgroundWorker входит в раздел lock{}, другие, которые приходят в эту точку, будут заблокированы. Поэтому важно убедиться, что код в заблокированном разделе выполняется быстро.

Когда вы приходите на "вывод" обработанного изображения, будьте осторожны, чтобы убедиться, что вы не выполняете кросс-потоковое обновление для пользовательского интерфейса. Проверьте этот пост, чтобы избежать этого.

Ответ 3

В окнах не только вы должны получать доступ только к элементам управления из одного потока, но этот поток должен быть основным потоком приложения, потоком, который создал элемент управления.

Это означает, что в DoWork вы не должны обращаться к каким-либо элементам управления (без использования Control.Invoke). Таким образом, вы бы назвали RunWorkerAsync, проходящий в вашем клоне изображения. Внутри обработчика событий DoWork вы можете извлечь параметр из DoWorkEventArgs.Argument.

Только обработчики событий ProgressChanged и RunWorkerCompleted должны взаимодействовать с графическим интерфейсом.