Если объект, которому нужен доступ к контейнеру, является бобом в контейнере, просто реализуйте BeanFactoryAware или интерфейсы ApplicationContextAware.
, Если объекту вне контейнера нужен доступ к контейнеру, я использовал стандартный шаблон "одиночка" GoF для пружинного контейнера. Тем путем у Вас только есть один одиночный элемент в Вашем приложении, остальные - все одноэлементные бобы в контейнере.
Внутри GDI + есть блокировка, которая предотвращает одновременный доступ двух потоков к битовой карте. Это не блокирующая блокировка, это блокировка типа «программист сделал что-то не так, я выдаю исключение». Ваши потоки бомбят, потому что вы клонируете изображение (== обращаетесь к растровому изображению) во всех потоках. Ваш поток пользовательского интерфейса бомбит, потому что он пытается нарисовать растровое изображение (== доступ к растровому изображению) в то же время, когда поток клонирует его.
Вам нужно ограничить доступ к растровому изображению только одним потоком. Клонируйте изображения в потоке пользовательского интерфейса перед запуском BGW, для каждого BGW требуется собственная копия изображения. Обновите свойство изображения PB в событии RunWorkerCompleted. Таким образом вы потеряете часть параллелизма, но это неизбежно.
В формах Windows вы должны не только получать доступ к элементам управления из одного потока, но этот поток должен быть основным потоком приложения , поток, создавший элемент управления.
Это означает, что в DoWork вы не должны обращаться ни к каким элементам управления (без использования Control.Invoke). Итак, здесь вы должны вызвать RunWorkerAsync, передавая клон вашего изображения. Внутри обработчика событий DoWork вы можете извлечь параметр из DoWorkEventArgs.Argument.
Только обработчики событий ProgressChanged и RunWorkerCompleted должны взаимодействовать с графическим интерфейсом пользователя.
Похоже, ваши BackgroundWorkers пытаются получить доступ к одним и тем же компонентам Windows Forms одновременно. Это объясняет, почему сбой является случайным.
Вам нужно убедиться, что этого не происходит, используя блокировку
, возможно, так:
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 установлен. local для этого метода - вы определенно не хотите использовать его для всех методов!
С другой стороны, один и тот же экземпляр lockObject используется всеми методами. Когда метод BackgroundWorker входит в свою секцию lock {}
, другие, которые дошли до этой точки, будут заблокированы. Поэтому важно убедиться, что код в заблокированной секции работает быстро.
Когда вы приходите к «выводу» обработанного изображения, также будьте осторожны, чтобы убедиться, что вы не выполняете межпотоковое обновление пользовательского интерфейса. .