2009-06-29 2 views
30

У меня есть настольное приложение C#, в котором один поток, который я создаю, непрерывно получает изображение из источника (это фактически цифровая камера) и помещает его на панель (панель. изображение = IMG) в GUI (который должен быть другой поток, как это отделенного кода элемента управления.InvalidOperationException - объект в настоящее время используется в другом месте - красный крест

приложение работает, но на некоторых машинах, которые я получаю следующее сообщение об ошибке в случайные промежутки времени (непредсказуемый)

************** Exception Text ************** 
System.InvalidOperationException: The object is currently in use elsewhere. 

Затем панель превращается в красный крест, красный X - я думаю, что это недопустимый значок изображения, который можно редактировать из свойств. ион продолжает работать, но панель никогда не обновляется.

Из того, что я могу сказать, эта ошибка возникает из события onpaint элемента управления, где я рисую что-то еще на картинке.

Я попытался с помощью замка там, но не повезло :(

Как я вызвать функцию, которая помещает изображение на панели следующим образом:

if (this.ReceivedFrame != null) 
{ 
    Delegate[] clients = this.ReceivedFrame.GetInvocationList(); 
    foreach (Delegate del in clients) 
    { 
     try 
     { 
      del.DynamicInvoke(new object[] { this, 
       new StreamEventArgs(frame)}); 
     } 
     catch { } 
    } 
} 

это делегат:

public delegate void ReceivedFrameEventHandler(object sender, StreamEventArgs e); 
    public event ReceivedFrameEventHandler ReceivedFrame; 

и это, как функция внутри элемента управления фоновым кодом регистрирует к нему:

Camera.ReceivedFrame += 
    new Camera.ReceivedFrameEventHandler(camera_ReceivedFrame); 

Я также попытался

del.Method.Invoke(del.Target, new object[] { this, new StreamEventArgs(b) }); 

вместо

del.DynamicInvoke(new object[] { this, new StreamEventArgs(frame) }); 

, но не повезло

Кто-нибудь знает, как я могу исправить эту ошибку, или, по крайней мере поймать ошибку как-то и сделать нить снова поместите изображения на панель?

ответ

0

Я думаю, что это многопоточность проблемы Используйте окно золотого правило и обновить панель в главном использовании нити panel.Invoke Это должно преодолеть перекрестное исключение потоковой

+0

Я обновляю панель в основном потоке, но я вызываю функцию, которая обновляет ее из другого потока и передает изображение в качестве параметра. – 2009-06-29 20:39:53

+0

, если вы вызываете функцию, которая обновляет панель из другого потока, а в самой функции отсутствует переключение контекста (например, переключиться на основной поток, используя вызов), это означает, что ваше обновление выполнено на другом потоке, а не на главном потоке –

18

Это потому, что Gdi + класс изображения не поточно. Hovewer вы можете избежать InvalidOperationException, используя блокировку каждый раз, когда вам нужно получить доступ изображения, например, для живописи или получить размер изображения:

Image DummyImage; 

// Paint 
lock (DummyImage) 
    e.Graphics.DrawImage(DummyImage, 10, 10); 

// Access Image properties 
Size ImageSize; 
lock (DummyImage) 
    ImageSize = DummyImage.Size; 

Кстати, вызов не требуется, если вы будете использовать вышеупомянутую картину.

+0

well my функция, которая запускается внутри события onpaint, рисует много материала на панели над изображением, которую накладывает другой поток на панели, и как я могу заблокировать everithing, который нарисован? это включает в себя прямоугольники, линии и изображения. – 2009-06-29 20:41:46

+0

Я привязал блокировку панели, но она не сработала. Я все еще получил ошибку. – 2009-06-29 20:42:25

+0

Вам не нужно блокировать панель, вам нужно заблокировать конкретное изображение, с которым вы работаете. – arbiter

2

Мне кажется, что тот же объект камеры используется несколько раз.

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

Я запрограммировал что-то подобное один раз, после каждого полученного кадра нам потребовалось получить следующий кадр и установить в этом запросе буфер приема NEW.

Если вы не можете этого сделать, скопируйте полученный кадр из камеры сначала в новый буфер и добавьте этот буфер в очередь или просто используйте 2 чередующихся буфера и проверьте перерасход. Либо используйте myOutPutPanel.BeginInvoke для вызова метода camera_ReceivedFrame, либо лучше иметь поток, который проверяет очередь, когда у нее есть новая запись, которую он вызывает mnyOutPutPanel.BeginInvoke, чтобы вызвать ваш метод, чтобы установить новый буфер как изображение на панели.

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

В приведенном ниже примере можно вызвать из любого потока (библиотека захвата или другой отдельный поток):

void camera_ReceivedFrame(object sender, StreamEventArgs e) 
{ 
    if(myOutputPanel.InvokeRequired) 
    { 
     myOutPutPanel.BeginInvoke( 
      new Camera.ReceivedFrameEventHandler(camera_ReceivedFrame), 
      sender, 
      e); 
    } 
    else 
    { 
     myOutPutPanel.Image = e.Image; 
    } 
} 
4

У меня была аналогичная проблема с тем же сообщением об ошибке, но попробовать, как я мог бы, запирая растровое Ждут» что-нибудь для меня. Затем я понял, что рисую фигуру с помощью статической кисти. Разумеется, это была кисть, которая вызывала конфликт потоков.

var location = new Rectangle(100, 100, 500, 500); 
var brush = MyClass.RED_BRUSH; 
lock(brush) 
    e.Graphics.FillRectangle(brush, location); 

Это работает для моего случая и урок: Проверьте все типы ссылок используются в точке, где нить утверждение происходит.

+1

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

Смежные вопросы