Wielowątkowy dostęp do picturebox-a

0

Cześć wszystkim

Sytuacja wygląda tak:
Mam na formatce picturebox-a "Mapa"
Mam kilka(naście/dziesiąt) obiektów "skrzyzowanie_nr", z których każdy ma w sobie wątek generujący co zadany czas zdarzenie ZmianaSwiatel
W formatce z Mapą mam metodę reagująca na te zdarzenia

 private void skrzyzowanie_ZmianaSwiatel(string nazwa_skrzyzowania, int ktore_zielone)
{
            if (tabControl1.SelectedIndex == 1) //zmieniaj swiatla tylko w trybie symulacyjnym
            {
                //rwl.EnterReadLock();
                Monitor.Enter(Latch);
                Graphics graf = Graphics.FromImage(mapa_symulacyjna.Image); **//TU JEST BŁĄD: Obiekt jest obecnie używany gdzie indziej!!!!!!!**
                //rwl.ExitReadLock();
                Image syg_z = Image.FromFile(@"obrazki_symulacyjne\sygnalizator_zielony.png");

                if (ktore_zielone >= 0)
                {
                    if (ktore_zielone == 0)
                    {
                        //rwl.EnterWriteLock();
                        graf.DrawImage(syg_z, (tlo_projektowe.Controls[nazwa_skrzyzowania + "p"] as PictureBox).Left + skok + 2, (tlo_projektowe.Controls[nazwa_skrzyzowania + "p"] as PictureBox).Top + skok + 4, 13, 13);
                        mapa_symulacyjna.Invalidate();
                        //rwl.ExitWriteLock();
                    }
                    if (ktore_zielone == 1)
                    {
                        //rwl.EnterWriteLock();
                        graf.DrawImage(syg_z, (tlo_projektowe.Controls[nazwa_skrzyzowania + "p"] as PictureBox).Left - 17, (tlo_projektowe.Controls[nazwa_skrzyzowania + "p"] as PictureBox).Top + skok + 2, 13, 13);
                        mapa_symulacyjna.Invalidate();
                        //rwl.ExitWriteLock();
                    }
                }                
                syg_cz.Dispose();
                syg_z.Dispose();
                graf.Dispose();
                Monitor.Exit(Latch);
            }            
        }

Jak widać próbowałem z ReaderWriterLockSlim (obiekt rwl), próbowałem z Monitorem ale błąd "Obiekt jest obecnie używany gdzie indziej!" jak był tak jest.

Czy wiecie jak jeszcze mogę się przed tym zabezpieczyć tak żeby wszystkie wątki mogły sobie rysować po jednej mapie?

0

Metoda która pokazałeś wykonuje się w wątku, a mapa_symulacyjna to twoja kontrolka?Jeśli tak to próbujesz się dostać do kontrolek z innego wątku niż wątek w którym zostały utworzone. Poszukaj o Invoke, BeginInvoke.

0
adams85 napisał(a)

Metoda która pokazałeś wykonuje się w wątku, a mapa_symulacyjna to twoja kontrolka?Jeśli tak to próbujesz się dostać do kontrolek z innego wątku niż wątek w którym zostały utworzone. Poszukaj o Invoke, BeginInvoke.

Metoda jest w watku głównym tam gdzie picturebox mapa_symulacyjna i odbiera zdarzenia z innych wątków.
Wspólpraca między wątkami działa prawidłowo własnie dzięki zdarzeniom.
I wszystko jest OK jesli mam kilka skrzyzowan, ale przy większej ich liczbie w końcu sie zdarza że kilka z nich jednocześnie wysyla zdarzenie które w rezultacie rysuje po tej samej mapie.

0

Jak uruchamiam z debugowaniem to mam w "if (tabControl1.SelectedIndex == 1)":
Nieprawidłowa operacja między wątkami: do formantu 'tabControl1' uzyskiwany jest dostęp z wątku innego niż wątek, w którym został utworzony.
błąd jest od razu po zmianie zakładki w tabControl1

a jak bez debugowania to w linii "Graphics graf = Graphics.FromImage(mapa_symulacyjna.Image);":
Obiekt jest obecnie używany gdzie indziej.
Bład pojawia sie po kilku sekundach gdy dwa wątki sie pogryzą

kiedy mam dwa skrzyżowania (obiekty z wątkami) to program bez debugowania sie uruchamia i działa bez problemu

0

Dokładnie tak, jak napisał adams85, wykonujesz niedozwoloną operację między wątkami. Nie możesz odwoływać się do GUI z wątków innych niż wątek GUI.
Rozwiązanie: http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.80%29.aspx

0

Wiem że nie mogę, ale tak sie składa że dzięki zdarzeniu własnie to robie i przy dwóch obiektach (każdy z własnym wątkiem) nawet mi sie to udaje, program działa jak należy!
Powtarzam: bez debugowania program z kilkoma takimi obiektami uruchamia się i działa kilka sekund!
Problem pojawia się wtedy gdy jeden wątek chce odczytać pictureboxa, a inny właśnie po nim rysuje.

0

Ok, masz swoją wersję, to sobie w nią wierz. Możesz sobie zrobić nawet ołtarzyk z tymi swoimi zdarzeniami i codziennie się do niego modlić.
Nikt Ci nie zabroni pisania nieprawidłowego i niezgodnego z zasadami kodu. Nikt Ci nie każe słuchać naszych rad. Tylko po co prosisz o pomoc, skoro nie chcesz z niej skorzystać?

0

Oto ja, niedoświadczony programista, publicznie przyznaję się do błędu i proszę o wybaczenie osoby, które chciały mi pomóc.
I pomogły. "Sztuczka" z delegatem i invoke działa.
Ostatnio żyje w ciągłym stresie bo czas nagli, a tu co rusz jakieś nowe błedy w kodzie.
Przepraszam.

0

Ty nie przepraszaj nas tylko siebie, bo sam sobie szkodzisz. Nie mielibyśmy żadnego interesu w oszukiwaniu Ciebie. ;)

0
Bagietka napisał(a)

"Sztuczka" z delegatem i invoke działa.

To nie jest sztuczka, to po prostu bezpieczne przekazanie instrukcji do wątku głównego, bo w nim tworzone są kontrolki i tylko on ma prawo w nich grzebać. Więcej o tym pod linkiem od somekind'a

Bagietka napisał(a)

Problem pojawia się wtedy gdy jeden wątek chce odczytać pictureboxa, a inny właśnie po nim rysuje.

Rozumiem, że miałeś na myśli wątki poboczne. Patrząc na twój program powiem, że to niemożliwe. Przecież przed odwołaniem się do pictureboxa zakładasz zamek, więc jakiekolwiek dwa wątki poboczne nie będą miały do niego dostępu w tym samym czasie(no chyba, że odwołujesz się do niego gdzieś indziej)

1 użytkowników online, w tym zalogowanych: 0, gości: 1