Czekanie na zakończenie wątków - problem

0

Witam, mam następującą metodę w głównej klasie formy:

private void btnExecute_Click(object sender, EventArgs e)
            if (isDo)
            {
                Thread thMax = new Thread(new ThreadStart(this.ThreadProcZoomax));

                Thread thMed = new Thread(new ThreadStart(this.ThreadProcZoomed));
                thMed.IsBackground = true;

                Thread thMin = new Thread(new ThreadStart(this.ThreadProcZoomin));
                thMin.IsBackground = true;

                imageMed = ImageUtils.ResizeImage(this.image, 50.0);
                imageMin = ImageUtils.ResizeImage(this.image, 20.0);
                ImageUtils.form = this;

                this.Enabled = false;
                thMax.Start();
                thMed.Start();
                thMin.Start();
            }


            //TO SIĘ MA WYŚWIETLIĆ PO ZAKOŃCZENIU WĄTKÓW
            this.Enabled = true;
            MessageBox.Show("Operacja zakończona powodzeniem", "Powodzenie", MessageBoxButtons.OK, MessageBoxIcon.Information);

            panelBottom.Visible = true;
            progressBar.Visible = false;
            progressBar.Value = progressBar.Minimum;
        }

Mój problem polega na tym, że nie wiem jak zrobić aby ten fragment który jest oznaczony komentarzem,
wykonał się dopiero po zakończeniu działania wątków. Próbowałem thMax.Join(), ale musiałem źle zrozumieć
jak to działa, bo gdy to zastosuję to nic się nie dzieje, wątek i forma stoją...
Bardzo bym prosił o pomoc jak to rozwiązać. Chciałbym zaznaczyć, że to moja pierwsza przygoda z wątkami.
Zamieściłem ten post na innym forum wcześniej, ale nie dostałem odpowiedzi, więc mam nadzieję że tutaj ktoś mógłby pomóc.

1

Join tylko sprawia że okno "czeka" na zakończenie pracy wątku. Możesz spróbować thread.abort, (ale spowoduje to wywołanie threadabortexception możesz dodać obsługę wjątków i go zignorować), ale używanie tej metody to jak hamowanie auta na ręcznym - raczej nie jest to poprawny standardowy sposób. kiedy wątek wykona swoją pracę to sam się zwalnia. - musisz sam pomyśleć jak zmusić wątek do "skończenia się".

0

niezrozumiałeś, ja nie chcę zakańczać żadnego wątku, ja chcę tylko zaczekać w wątku głównym na zakończenie wątków które utworzyłem: thMax, thMin, thMed i wywołać operacje oznaczone komentarzem po zakończeniu wszystkich tych wątków.

1

Aha, no to w takim razie Join jak najbardziej się nadaje 0_o jesteś pewien że wątek roboczy kończy kiedyś swoje działanie? (wstaw gdzieś w procedurze breakpoint może)

Ew. dodaj mu w nawiasach timeout (np. thMax.Join(1000); ). Ogólnie to nie mam pomysłu co się dzieje :/

0

czyli jednak dobrze zrozumiałem działanie Join(), jednak jak to zrobie tak:
thMax.Start();
thMax.Join(); program nic nie robi, stoi, natomiast bez Join działa dobrze, tylko że MessageBox wyświetlany jest od razu zamiast zaczekać na zakończenie thMax.

Nie wiem jak sobie z tym poradzić :-/

0

To znaczy że thMax się u ciebie nigdy kończy.

0
Azarien napisał(a)

To znaczy że thMax się u ciebie nigdy kończy.

przecież napisałem że jak nie dam Join() to działa dobrze tylko MessageBox zamiast na końcu, pojawia się na początku, nie czekając na zakończenie wątku, a potem kończy swoje działanie. Więc to nie to.
Czy wątek thMax mogę bardzo łatwo sprawdzić, bo ten zapisuje on po kolei na dysku pliki, natomiast przy Join(), zapisze tylko pierwszy plik a potem stoi, żadne pliki się nie pojawiają

1

0_o? To może przejedź po wątku debbugerem? Albo podaj kod thmax albo chociaż newralgiczne fragmenty... Jeśli nie tajne oczywiście ;)

EDIT: I próbowałeś dać mu timeout w nawiasach? ( thMax.Join(1000); ) Na pewno nie rozwiąże to problemu,ale może stanie się coś co da ci odpowiedź gdzie jest problem...

0

raczej nie ma sensu chyba wstawiać tego kodu, bo to jest zwykle cięcie obrazka, nie wiem tylko czy to ma jakieś znaczenie jeśli wątek podrzędny (thMax) korzysta z danych zawartych w klasie formy, a wątek tej formy zawieszam przez Join(), to czy dalej może korzystać z tych danych...? Nie jestem w tym obcykany niestety. A z timeoutem nie próbowałem.

Ale poradziłem sobie inaczej, przez ustawianie flag przez wątki, i gdy wszystkie flagi są ustawione to odpowiednia wiadomość jest wyświetlana.

1

...co nie zmienia faktu że skoro Join() działa dziwacznie to gdzieś w kodzie jest błąd który się może kiedyś ujawnić :/
Ale może tylko się czepiam :)

0

Najbardziej elegancko by bylo wysyłać z wątków eventy, które będą sygnalizować ich zakończenie. Eventy obsługujesz w watku głównym i wtedy wiesz kiedy zakończyły się wszystkie i możesz sobie wyświetlić komunikat.

Lub bardziej "po chamsku" - sprawdzać w timerze czy wątki żyją i jeżeli nie to wyświetlić co tam chcesz

0

z eventami też to jest pomysł, ale nie wiem jak dokładnie to rozwiązać dlatego zrobiłem flagi i każdy wątek zraz przed zakończeniem sprawdza czy wszystkie flagi są ustawione, jeśli tak to ten ostatni wyświetla MessageBox. Może to nie jest zbyt profesjonalnie ale działa i nawet jestem bardziej zadowolony niż jakby to miało działaś z Join(). Chociaż czemu Join nie działa to dalej mnie nurtuje :-D

1

Bo zawsze może się okazać że wątki kończą pracę ale ciągle żyją, w skrajnym przypadku nawet po wyłączeniu programu [rotfl] . A tak serio to nie wiem czemu ci tak dziwnie chodzi, mi Jon() nigdy nie robił problemów :)

0

w skrajnym przypadku nawet po wyłączeniu programu

to nie dowcip, w takim przypadku nie ma możliwości zamknięcia programu inaczej niż przez jego ubicie z zewnątrz - proces wisi to zamknieciu głównego okna i po Application.Terminate

0

ok, to jak sprawdzić czy wątek jeszcze chodzi? Thread.IsAlive?
A moje wątki się raczej kończą, bo inaczej, po zamknięciu okna nie wracałoby do z powrotem do trybu edycji kodu w VS. Zresztą w okienku Output w VS piszę że w wątek wyszedł z kodem 0, więc powinno być dobrze :-)

0

krho: Twoje wątki się nie kończą!

Join() jest najbardziej odpowiednią metodą aby poczekać, aż dany wątek się zakończy. Jeśli aplikacja się "wiesza" czyli nic nie robi - Join() czeka, bo wątki (lub konkretny wątek) pracują.

Napisałeś, że jeśli nie ma Join() to wątki się kończą - a skąd to wiesz? Twoje wątki są typu Background - jak sam ustawiłeś. To oznacza, że jeśli zamykasz proces (aplikację) a wątki dalej działają - nie mają one siły utrzymywać procesu - giną razem z nim. Gdyby twoje wątki były typu Foreground - nie można by było zamknąć aplikacji - same by utrzymywały proces przy życiu.

Event czy flagi to paskudny sposób na komunikację pomiędzy wątkami. O wiele lepszy byłby AutoResetEvent - oraz metody : Set(), WaitOne(), WaitAll() - polecam lekturę MSDN.

Na twoim miejscu zaczął bym od zdebugowania metody ThreadProcZoomax.

0

Napisałeś, że jeśli nie ma Join() to wątki się kończą - a skąd to wiesz? Twoje wątki są typu Background - jak sam ustawiłeś. To oznacza, że jeśli zamykasz proces (aplikację) a wątki dalej działają - nie mają one siły utrzymywać procesu - giną razem z nim. Gdyby twoje wątki były typu Foreground - nie można by było zamknąć aplikacji - same by utrzymywały proces przy życiu.

Wiem że się kończą bo w VS, w okienku "Output" mam coś takiego (przed zamknięciem aplikacji oczywiście):

The thread 0xe2c has exited with code 0 (0x0).
The thread 0x142c has exited with code 0 (0x0).
The thread 0x11e0 has exited with code 0 (0x0).

A wątków uruchamiam akurat dokładnie 3.
oraz jak ustawiłem na IsBackground = false; aplikacja normalnie się zamknęła, co jeśli dobrze myślę to świadczy że jednak się kończą.

Napiszę to jeszcze raz: Gdy na thMax zrobię Join() wtedy wycina tylko jeden skrawek obrazu i go zapisuje na dysku. Widzę w tym folderze że żadne inne pliki się nie pojawiają, a ma ich być kilkadziesiąt. Natomiast bez Join() normlanie widzę jak pocięte pliki się pojawiają. Z tego wnioskuję, że thMax nie działa przy zastosowaniu Join(), program się nie zawiesza, ale też nic się nie dzieje, tylko stoi.

I teraz jeszcze jedno pytanie. Wątek thMax korzysta z danych w klasie Form, którą to wstrzymuję na czas działania tego wątku... A więc czy jak zawieszę dany wątek, to czy inne dalej mogą z niego (formy) odczytać dane?

A w MSDNie oczywiście poczytam o tych funkcjach.

0

Event czy flagi to paskudny sposób na komunikację pomiędzy wątkami.

Dlaczego? BackgroundWorker dziala dokladnie w ten sposob. Do przeprowadzenia jakiejs operacji w tle to chyba wystarczy, po co komplikowac sobie zycie?

1

Event czy flagi to paskudny sposób na komunikację pomiędzy wątkami.
Jeśli chodzi o flagi, to mi też się wydaje że to jakieś takie... nieeleganckie. Ale przeciwko eventom nic nie mam... Chociaż Deti ma rację - Set(), WaitOne(), WaitAll() są do tego chyba najlepsze.

PS. tak się zastanawiam czy do pierwotnego nie wystarczyłoby po prostu wywołanie asynchroniczne. :P

0

nie jestem jeszcze tak obcykany w .NET żeby to wszystko ogarnąć. Moje pierwsze użycie wątków i takie problemy się pojawiły. Może potem postaram się to bardziej elegancko zrobić, jeśli dowiem się jak to zrobić :-)

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