Wielowątkowość, kilka wątków ale jedno zadanie

0

Witam, drugi dzień borykam się z problemem następującym, piszę aplikacje która po wczytaniu listy plików będzie je pobierała, aby przyspieszyć proces samego pobierania (małe pliczki 400kb-1mb) postanowiłem uruchomić ten proces w kilku wątkach.

Mam wątki: (gdzieś dalej je nazwałem i ustawiłem isBackground na true)

        static Thread threadPage1 = new Thread(new ThreadStart(pageDownload));
        static Thread threadPage2 = new Thread(new ThreadStart(pageDownload));
        static Thread threadPage3 = new Thread(new ThreadStart(pageDownload));
        static Thread threadPage4 = new Thread(new ThreadStart(pageDownload));

Wszystkie startuje i dla testu napisałem pageDownload

        static private void pageDownload()
        {
            while (counter != 10)
            {
                System.Console.Write(".");
                Thread.Sleep(50);
                ++counter;
            }
            System.Console.WriteLine(string.Format("Pobieranie zakończone, wątek: {0}",  Thread.CurrentThread.Name));
            Thread.CurrentThread.Abort();
        }

Jednak to zabija tylko pierwszy wątek - tutaj różnie, który pierwszy skończy, a reszta leci w nieskończoność. Dziwne bo warunek w while powinien je zatrzymać, tak jakby inne wątki nie widziały zmiany w counterze.

2

Nic w tym dziwnego, musiałbyś mieć w sumie niezłego farta, żeby wszystkie wątki sprawdziły warunek w while w momencie w którym counter jest równy 10.
Ten Thread.CurrentThread.Abort() jest tu w ogóle bez sensu.

Poczytaj o synchronizacji wątków, w tym momencie nawet nie wiesz czy w momencie gdy dwa wątki zwiększą counter to on zwiększy się o 2 czy nie.

1

Rozszerzę wypowiedź byku_guzio. Przypuśćmy, że counter osiąga wartość 9. Jeden wątek zwiększa counter i sprawdza warunek w while. Jest 10, no to przerywa pętlę. Teraz inny wątek zwiększa counter i ten ma wartość już 11 więc warunek w while się nie spełnia. No to leci dalej aż do OverflowException na counter. W while warunek powinien być counter <= 10.

0

To tylko jedna część historii.
Może jeszcze wystąpić taka sytuacja w momencie ++counter: jeden wątek pobiera wartość counter, zostaje przerwany i drugi wątek podnosi wartość zmiennej counter, kontrolę znowu odzyskuje poprzedni wątek i przypisuje zmiennej counter wartość o jeden większą od tej, którą pobrał. W wyniku tego zmienna counter zwiększyła się tylko o 1, a nie o 2.

0

Nie, nie, nie. Zupełnie inaczej trzeba to zrobić.

Użyj jakiegoś TaskScheduler czy coś. W .NET jest masa mechanizmów do wielowątkowości.

0

Faktycznie, jakieś moje niedopatrzenie z warunkiem.

Poczytałem więcej o wątkach, jednak zwykle opisywane są sytuacje, w której ma być wykonywany wątek jeden po drugim.

Co do swojego problemu znalazłem chwilowe/częściowe rozwiązanie, dodać statyczny pusty obiekt, zastawić na nim lock'a

lock (mojObiekt) {
counter++;
}

Póki po prostu printuje tekst w konsolce jest wszystko ok, problem pojawia się przy próbie pobierania, bo zawsze tylko 3 z 4 wątków się kończy, ostatni albo działa w nieskończoność albo rzucaj wyjątkiem o przekroczeniu limitu czasu żądania.

A jakbym ustawił w webcliencie, aby pobierał asynchronicznie? Z opisu wnioskuję, że wtedy nie zablokuję wątku który go wywołał. Czyli na dobrą sprawę mógłbym mieć jeden wątek do pobierania, ustawić asynchronicznie a on sam by sobie tworzył wątki i w nich pobierał? Tylko, że linków mam ok 12 tyś. wrzucam je do kolejki i za każdym obrotem sprawdzam, czy w kolejce coś jeszcze jest następnie zdejmuję i obrabiam. Jeżeli wątek pobierający nie zablokuje wątku, który go wywołał to pewnie dostanę jakiś wyjątek o z informacją o przepełnieniu(?) ew. radykalnie spadnie wydajność przy tylu wątkach.

@offtopic
Tak przy okazji, bo nie umiem się nigdzie doszukać, czy jest możliwość zmiany tekstu już wypisanego w konsoli?
Chodzi mi o to, że chciałbym pokazać procentowo w jednym konkretnym miejscu ile już zostało pobrane/jest w trakcie. Nie będę czyścił konsoli przecież co chwilę, tylko zajmę czas procesora. Mam nadzieje, że zrozumiale.

1

czy jest możliwość zmiany tekstu już wypisanego w konsoli?
Console.CursorLeft, Console.CursorTop, Console.SetCursorPosition

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