Autor Wątek: InvokeRequired  (Przeczytany 2842 razy)

Offline Error.

  • Użytkownik

# Grudzień 28, 2011, 10:08:43
Witam.

Mógłby mi ktoś powiedzieć o co chodzi w "InvokeRequired"?
Wiem wiem, google, niestety wujek jest obcokrajowcem a do tłumaczenia takich zagadnień bardziej nadaję się rodak. :)

Chociaż coś wydedukowałem, na podstawie obserwowania "kodu złego" i "dobrego".

Błąd pojawia się gdy pracujemy na danych które są dostępne w 2 wątkach. Jeszcze z RC Coldwinda pamiętam że istnieje taka możliwość iż np jeden wątek pobiera daną wartość z pamięci, a 2 ją w tym momencie nadpisuję. I wtedy pojawia się problem, funkcja pobrała połowę "starego" kodu a połowę "nowego". I właśnie do tego służy "InvokeRequired" aby zrobić tam kopię obiektu i to na tej kopi operować.

Dobrze mówię?

Dziękuję i pozdrawiam.

PS:
I jeszcze jakby ktoś wyjaśnił mi co się dzieję w tej linijce:
textbox1.Invoke(new MethodInvoker(delegate { name = textbox1.text; }));Kiedy wywołują się te metody Invoke, dlaczego używamy tu delegacji, trochę czytałem o niej na google ale akurat w tym przypadku nie mogę zrozumieć jej zastosowania, to taka "funkcja bez nagłówka"?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Areal

  • Użytkownik

# Grudzień 28, 2011, 10:20:20
Tak, zgadza się, "problem" związany jest z pracą na wielu wątkach. Ogólnie rzecz biorąc, gdy pracujesz na wątku GUI (czyli normalnie z okienkami) to zmiany związane z interfejsem użytkownika mogą być dokonywane tylko z tego wątku. Teraz, gdy próbujesz z innego wątku dokonać zmian dostajesz exception. Aby rozwiązać ten problem stosuje się synchronizację poprzez użycie Invoke na którejś z kotrolek, wtedy twój kod w delegacie zostanie wykonany w wątku GUI.

Offline Error.

  • Użytkownik

# Grudzień 29, 2011, 09:43:53
Dzięki.
Mam jeszcze jedno pytanko.

Pracuje w innym wątku, gdy spróbowałem zmienić zmienną X która znajduje się w klasie głównej, do której przecież ma dostęp i mój wątek i wątek główny nie pojawił się błąd.

Dlaczego?

Problemu nie ma czy po prostu kompilator go nie zauważa?

PS: Aaaa! Chyba wiem! To typ bool, a bool to 0 i 1 a 0 i 1 to 1 bit więc wątki nie mogę się "pomylić". Dobrze wymyśliłem?

Offline Kos

  • Użytkownik
    • kos.gd

# Grudzień 29, 2011, 10:23:03
(edit: oh, wait, to C#)

Offline Esidar

  • Użytkownik

# Grudzień 29, 2011, 11:33:13
Problemu nie ma czy po prostu kompilator go nie zauważa?

PS: Aaaa! Chyba wiem! To typ bool, a bool to 0 i 1 a 0 i 1 to 1 bit więc wątki nie mogę się "pomylić". Dobrze wymyśliłem?
Kompilator nie wie z ilu wątków wykonywany jest kod. Ten wcześniejszy błąd "InvokeRequired" też pojawia się dopiero po uruchomieniu programu (po skompilowaniu).

Po drugie, dostęp do zmiennych jest na poziomie bajtów a nie bitów, więc nie dobrze "wymyśliłeś" :)  . Co więcej, jeżeli nie wiesz jakiego rodzaju problemy są związane z dostępem do zmiennych z poziomu kilku wątków (a problemów/niebezpieczeństw jest sporo), to polecałbym ci zmianę każdej zmiennej tylko na jednym wątku. Jeżeli chcesz zmienić zmienną na innym wątku, to zrób to za pomocą komunikatu/polecenia przekazywanego do wątku który jest uprawniony do zmiany zmiennej. Możesz się posłużyć klasami w namespace "System.Threading.Tasks".

Offline Error.

  • Użytkownik

# Grudzień 29, 2011, 12:16:57
Cytuj
Kompilator nie wie z ilu wątków wykonywany jest kod. Ten wcześniejszy błąd "InvokeRequired" też pojawia się dopiero po uruchomieniu programu (po skompilowaniu). Po drugie, dostęp do zmiennych jest na poziomie bajtów a nie bitów, więc nie dobrze "wymyśliłeś" :)
Ahh, szkoda.
Ale teraz żadnej błąd InvokeRequired nie pojawił się po skompilowaniu.

Ok, po małej koreckie w mojej funkcji timera na początku mam:
         
        if (lista_przyciskow.InvokeRequired)
            {
                lista_przyciskow.Invoke(new MethodInvoker(delegate {
                      // kopiowanie do zmiennych lokalnych
                }));
            }

Potem wykonuje obliczenia a na końcu:
            if (lista_przyciskow.InvokeRequired)
            {
                lista_przyciskow.Invoke(new MethodInvoker(delegate
                {
                 // aktualizowanie źródła z którego kopiowałem
                }));

1. Czy to dobry sposób?

2. Już pomijając że nie mam prawie żadnego pojęcia i tym co to jest delegate a już o jego praktycznym zastosowaniu nie wspominając to czy "mądre" jest ciągłe tworzenie nowej metody skoro jest ona taka sama?

3. Czy instrukcja if jest tutaj potrzebna? Przecież wiem że timer jest w innym wątku więc chyba nie muszę tego sprawdzać?


Dzięki za pomoc! :]

« Ostatnia zmiana: Grudzień 29, 2011, 12:19:27 wysłana przez Error. »

Offline Esidar

  • Użytkownik

# Grudzień 30, 2011, 16:49:27
1. Czy to dobry sposób?
Wystarczający :) Invoke od tego właśnie jest, żeby wykonać kod na wątku GUI.

2. Już pomijając że nie mam prawie żadnego pojęcia i tym co to jest delegate a już o jego praktycznym zastosowaniu nie wspominając to czy "mądre" jest ciągłe tworzenie nowej metody skoro jest ona taka sama?
Delegate to jest typ wskaźnika na funkcję. Kod który tam wpisałeś, kompilowany/tworzony jest tylko raz, a każde wywołanie delegate{} utworzy jedynie wskaźnik na ten kod i przekaże go do innego wątku.

3. Czy instrukcja if jest tutaj potrzebna? Przecież wiem że timer jest w innym wątku więc chyba nie muszę tego sprawdzać?
Dla spokoju możesz ten if zostawić. Nie wiem co by się stało gdyby Invoke wykonać na wątku GUI, ale podejrzewam że nic złego (kod byłby skolejkowany i wykonany w "wolnej chwili").