Wielowątkowy dostęp do picturebox-a

Wielowątkowy dostęp do picturebox-a
Bagietka
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 5 lat
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

Kopiuj
 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?


Nie trąb proszę. Ty też się kiedyś uczyłeś.
edytowany 1x, ostatnio: Bagietka
adams85
  • Rejestracja:ponad 15 lat
  • Ostatnio:około 14 lat
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.

edytowany 2x, ostatnio: adams85
Bagietka
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 5 lat
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.


Nie trąb proszę. Ty też się kiedyś uczyłeś.
adams85
Metoda uruchomiona z wątku cały czas działa w kontekście tego wątku, nie w wątku głównym. Podaj dokładną treść wyjątku
Bagietka
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 5 lat
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


Nie trąb proszę. Ty też się kiedyś uczyłeś.
edytowany 1x, ostatnio: Bagietka
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Wrocław
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

Bagietka
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 5 lat
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.


Nie trąb proszę. Ty też się kiedyś uczyłeś.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Wrocław
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ć?

Bagietka
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 5 lat
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.


Nie trąb proszę. Ty też się kiedyś uczyłeś.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:2 minuty
  • Lokalizacja:Wrocław
0

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

adams85
  • Rejestracja:ponad 15 lat
  • Ostatnio:około 14 lat
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)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)