idepozapalki Temat założony przez niniejszego użytkownika |
[WinApi] Sprawdzanie uruchomionego wątku. » 2023-05-03 17:53:01 Dzień dobry, Miałbym pytanie do lekcji o wątkach. Mianowicie jak sprawdzić czy wątek aktualnie "ma zajęcie" ? Przykładowo uruchamiam 10 wątków: HANDLE hThread =( HANDLE ) _beginthread( ThreadProc, 0, NULL );
i one będą aż do zamknięcia programu. Teraz chciałbym, żeby wolny wątek coś policzył. Obliczenia mogą różnie trwać. Czy jest jakieś eleganckie rozwiązanie które może dać odpowiedź który wątek akurat jest wolny i można przydzielić mu pracę? W wątkowej pomocy Microsoftu nie znalazłem funkcji typu: isthreadbusy() sprawdzającej czy _beginthread czyś aktualnie się zajmuje. Moim pierwszym skojarzeniem jest struktura: struct Watek { bool watek1; bool watek2; itd ... };
I uzupełnianie jej informacją przez wątki: wątek nie pracuje false, pracuje true |
|
DejaVu |
» 2023-05-06 12:31:16 Nie twórz wątków jeżeli nie masz dla nich dedykowanych zadań. Ewentualnie możesz zaimplementować sobie tzw. ThreadPool, która polega na tym, że dodajesz zadania do wykonania do jednej współdzielonej kolejki i każdy wątek przypisany do obsługi 'zadań z thread poola' pobiera pierwsze oczekujące zadanie z kolejki, wykonuje je i wraca do początku tj. oczekiwania na kolejne zadanie. class Task { public: typedef std::shared_ptr < Task > Ref; };
void ThreadPoolWorker::TheadLoop( ThreadPool & _pool ) { while( _pool.keepRunning ) { refTask = _pool.popTask( refTask ) if( refTask != null ) refTask->Execute(); else Sleep( 10 ); } }
Rozwiązanie to jest dość prymitywne i jeżeli chciałbyś zaimplementować to lepiej to musiałbyś użyć mutexów i zaimplementować metodę 'popTask' w taki sposób, aby jej wykonanie było blokowane jeżeli nie ma żadnych oczekujących elementów na liście. Ponadto musiałbyś zaimplementować mechanizm, aby odblokować listę i zwracać 'null' w przypadku, gdy ThreadPool będziesz chciał, aby został zniszczony (np. przy zamykaniu aplikacji), aby wątki wiedziały, że mają zakończyć przetwarzanie zadań i się wyłączyć. Wówczas "sleep" nie będzie potrzebny i zadania 'natychmiast' będą 'konsumowane' do przetworzenia więc będziesz wykorzystywał najefektywniej wątki. Jakbyś szukał sobie materiałów po polsku to thread pool tłumaczy się na pula wątków. |
|
idepozapalki Temat założony przez niniejszego użytkownika |
» 2023-05-17 12:52:10 Już tłumaczę w czym właściwie mam problem. Otóż w tym momencie uruchamiam dedykowany wątek w taki sposób: std::thread worker( worker_thread, i ); worker.detach();
Problem pojawia się przy zamykaniu przeliczającej coś aplikacji. Oczywiście w tym wątku umieszczone są w pętlach warunki przerywające ich działanie w przypadku otrzymania informacji, że program jest zamykany. Poza pętlami na kolejnych etapach pracy wątku dodałem również warunki sprawdzające czy jest sygnał o przerwaniu i wtedy kończy się praca. Testowanie aplikacji pokazało, że przerywanie pętli nie działa prawidłowo. To znaczy, że aplikacja wyrzuca błąd przy próbie zamykania gdy wątek liczy. Sytuację poprawia danie 0,5 sekundy czasu oczekiwania przed zamykaniem, ale to też nie zawsze działa i liczący wątek nie jest przerwany prawidłowo. Poszperałem i znalazłem rozwiązanie polegające na uruchomieniu kilku wątków z jednym osobnym wątkiem służącym do zamykania pozostałych. Pomyślałem, że to może mieć sens w moim przypadku. Osobny wątek zaczeka i zadba o posprzątanie wszystkiego. |
|
pekfos |
» 2023-05-17 16:27:44 Nie powinieneś robić detach(), tylko zachować obiekt std::thread i wykonać na nim join() po wydaniu sygnału stopu, żeby zaczekać na jego zakończenie. |
|
idepozapalki Temat założony przez niniejszego użytkownika |
» 2023-05-17 17:25:52 join() niestety się tutaj nie sprawdza, a szkoda. Co prawda zrobi swoją robotę, ale wątek w trakcie przetwarzania przekazuje informacje o etapach swojej pracy do GUI, a tam nic się nie zaktualizuje dopóki wątek się nie zakończy. Wtedy dostaję informację o 100% przetworzenia danych, ale do tego momentu aplikacja sprawia wrażenie zamrożonej.
detach() robi to co trzeba i GUI też na bieżąco informuje o wszystkim na progresbarze jednak stwarza problemy gdy jest w trakcie pracy, a użytkownik zdecyduje się jednak tą pracę anulować i zakończyć aplikację. Wtedy są problemy o których wyżej wspomniałem.
Początkowo sądziłem, że gdy wydam sygnał stopu to wątek zostanie przerwany i destruktory posprzątają wszystko po sobie jednak po testach okazało się, że przy różnej ilości przetwarzanych danych nie wygląda to już tak różowo. Wprawdzie można by machnąć ręką na to "awaryjne" zamykanie jednak wyglądałoby to strasznie nieelegancko. |
|
pekfos |
» 2023-05-17 21:10:22 join() niestety się tutaj nie sprawdza, a szkoda. Co prawda zrobi swoją robotę, ale wątek w trakcie przetwarzania przekazuje informacje o etapach swojej pracy do GUI, a tam nic się nie zaktualizuje dopóki wątek się nie zakończy. Brzmi jakbyś po prostu wstawił join() w miejsce detach(). Miałeś zachować obiekt std::thread i wykonać na nim join() po wydaniu sygnału stopu. Czy natychmiast po zleceniu zadania chcesz czekać na jego zakończenie i blokować GUI? Chyba nie. |
|
idepozapalki Temat założony przez niniejszego użytkownika |
» 2023-05-17 22:48:10 Tak, po prostu zamieniałem join() na detach().
Na swoje usprawiedliwienie napiszę, że nie drążyłem tego kierunku gdyż w trakcie testów wyszło, że jeden wątek obsługujący przeliczanie jest "niezbyt fortunnym" rozwiązaniem. Dlatego zwróciłem się w kierunku kilku wątków. To niezbyt "fortunne rozwiązanie" polega na tym, że program uruchamiany jest tylko w jednej instancji. Jeden z powodów akurat tego jest taki, żeby widzieć graficzne wyniki przetwarzania wszystkich przeliczeń w jednym miejscu GUI, a nie szukać ich w wielu pootwieranych okienkach na pasku. W trakcie testowania wyszło, że zajęcie jednego przeliczającego wątku długim przeliczaniem (koło 30 minut) tak naprawdę blokuje aplikacje na ten okres. W tym czasie może pojawić się konieczność przeliczenia czegoś małego i krótkiego (czym mógłby zająć się inny wątek), ale trzeba zaczekać aż przeliczy się to długie zadanie. |
|
pekfos |
» 2023-05-18 17:09:40 Tylko co to ma do rzeczy? Utwórz i sto wątków, jeśli musisz. Nie znaczy że masz je zaraz gubić robiąc detach(). |
|
« 1 » |