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
}

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

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

Я понятия не имею, что происходит.


person claws    schedule 05.12.2009    source источник


Ответы (4)


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

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

person Hans Passant    schedule 05.12.2009

Таким образом, похоже, что ваши 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{} раздел, все остальные, дошедшие до этой точки, будут заблокированы. Поэтому важно убедиться, что код в заблокированном разделе работает быстро.

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

person Jeremy McGee    schedule 05.12.2009

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

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

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

person DW.    schedule 05.12.2009

Когда я пытался получить доступ к компоненту основного потока (PictureBox) из разных потоков, у меня также было System.InvalidOperationException: Объект в настоящее время используется

MethodInvoker Delegate решил проблему.

Invoke((MethodInvoker)(delegate ()
{
   var image = PictureBox.Image;
}));
person Ma'ruf    schedule 14.10.2020