Jarosław Rybski

Jarosław Rybski Programista
C/C++/Python

Temat: Zaczekać na zakończenie wątków

Witam,

Mam problem z jednym zadaniem - początkowo wszystko wydawało się proste i logiczne ale jednak moja analiza poszła dalej i powstał problem.

Serwer - wykorzystuje protokół TCP/IP coś na styl ala gadu-gadu.
Jest pętla

while(1)
{
accept(...) // akceptacja na przyłączenie klienta
pthread_create fun_do_obsługi_klienta()
lub _beginthread
}
WaitForMultipleObject(ile_watkow ...)
cout << "koniec programu"


To właśnie jest problem - w jaki sposób wykryć że wszystkie wątki uległy zakończeniu? Myślałem że WaitForMultipleObject będzie odpowiednia ale raczej nic z tego. Wątków mogę utworzyć dowolną ilość - czyli np aktualnie jest podłączonych 5 klientów i każdy ma swój wątek a za chwilę będzie ich 55 - czyli dynamicznie zmieniająca się ilość wątków.
Każdy klient który się podłączy do serwera może być zalogowany zarówno na 10 sekund jak i na godzinę - wylogowanie się klienta jest równoznaczne z zakończeniem się wątku. Oczywiście pętla jest tak zbudowana aby się kręciła bez końca jednak chciałbym na czas testów zobaczyć jak to wszystko będzie ze sobą współgrało i co pokaże Valgrind.

Kolejnym elementem który mnie zastanawia to jak powinien być zaimplementowany serwer mogący obsłużyć jednocześnie 10tys klientów. W WinXP proces utworzył ponad 600 wątków do obsługi klientów jednak nie mogę powiedzieć żeby ten program płynnie pracował a system to praktycznie zadyszki dostał.

Pozdrawiam.
Jakub L.

Jakub L. Programista

Temat: Zaczekać na zakończenie wątków

Po windzianemu zrobiłbym, że w wątku potomnym przed zamknięciem słane by było coś do wątku serwerowego - zdarzenie dla WaitForMultiple... albo message (no tu jest zaleta że nie jesteś ograniczony przez z góry narzuconą liczbę uchwytów) i ów ewentualny sygnał obrabiałbym obok accept.
Inna rzecz że jak masz while(1), to nie za bardzo widzę jak miałby dojść do WaitFor... :).
Po unixianemu to nie wiem jak się nazywają funkcje

Temat: Zaczekać na zakończenie wątków

wykrycie zakonczenia wszystkich watkow mozna zrobic na kilka sposobow:
1. koncepcja (chyba) posix only - uzywasz jakiejs zmiennej (licznika) typu sig_atomic_t i obrabiasz ja w funkcjach/makrach pthread_cleanup_pop i pthread_cleanup_push,
2. ustawiasz jakis semafor zliczajacy, na ktorym zliczasz pojawiania sie i znikania kolejnych watkow (a licznik zmieniasz na poczatku i koncu glownej funkcji watka).
3. po utworzeniu watka pamietasz jego uchwyt i probojesz za kazdym razem pobrac status konca watka. jak sie uda, to watka juz nie ma. jak sie nie uda - najpewniej jeszcze sie kreci.
4. oraz rozne wariacje/mieszanie powyzszych metod oraz kilka innych, bardziej zamieszanych.
jest tutaj tylko 1 problem - prawdopodobnie na wejsciu do petli nie bedzie dzialajacych watkow, wiec musisz tutaj jakas logike dac, zeby na samym starcie nie zakonczyc petli.
co do mnostwa watkow - jak bedziesz operowal rozmiarem stosu (zmniejszal go), to osiagniesz wieksza ilosc watkow - ale jak dasz za maly stos, to bedziesz mial wyloty.
zwykle sie to robi tak, ze kazdy watek obsluguje wiele polaczen.
Piotr P.

Piotr P. Software Developer

Temat: Zaczekać na zakończenie wątków

Jarosław Rybski:
Kolejnym elementem który mnie zastanawia to jak powinien być zaimplementowany serwer mogący obsłużyć jednocześnie 10tys klientów. W WinXP proces utworzył ponad 600 wątków do obsługi klientów jednak nie mogę powiedzieć żeby ten program płynnie pracował a system to praktycznie zadyszki dostał.

A nie wydajniej jest tworzyć procesy potomne? Wątki w aplikacji serwerowej nie pomogą Ci za bardzo z wydajnością nawet jeśli masz 100 jednostek CPU. Twoją pętle zastąpisz z powodzeniem wykorzystując g_main_loop z GLib'a.

Temat: Zaczekać na zakończenie wątków

najlepiej by bylo zrobic x procesow potomnych i kazdy z y watkami. do tego pamiec dzielona i mozemy szalec.
ale najpierw niech kolega watki opanuje.
z drugiej strony - trzeba jakos okreslic ile faktycznie ma byc tych klientow jednoczesnie (to pewnie gdzies w zalozeniach projektu jest), bo jak sie uprzec to mamy 30k procesow, a kazdy z kilkuset watkami. tylko czy to naprawde jest potrzebne?
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: Zaczekać na zakończenie wątków

Jarosław Rybski:
To właśnie jest problem - w jaki sposób wykryć że wszystkie wątki uległy zakończeniu?

Podobnie jak sugerował już Rafał, synchronizację pomiędzy wątkami oparłbym na semaforach lub podobnym im mechanizmach.
Chodzi o to, aby w sposób zsynchronizowany realizować komunikację pomiędzy grupą wątków roboczych, a wątkiem zarządzającym grupą wątków roboczych.

Pozdro, Adam Woźniak
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: Zaczekać na zakończenie wątków

Piotr P.:
[..] Wątki w aplikacji serwerowej nie pomogą Ci za bardzo z wydajnością nawet jeśli masz 100 jednostek CPU. [..]

Yyyy... Możesz rozwinąć tę tezę? Bo trochę mnie ta teza zadziwiła.

Pozdro, Adam Woźniak

konto usunięte

Temat: Zaczekać na zakończenie wątków

Adam Woźniak:
Piotr P.:
[..] Wątki w aplikacji serwerowej nie pomogą Ci za bardzo z
wydajnością nawet jeśli masz 100 jednostek CPU. [..]

Yyyy... Możesz rozwinąć tę tezę? Bo trochę mnie ta teza
zadziwiła.

Pozdro, Adam Woźniak

Wątki raczej pogarszają wydajność... Tracisz czas na semafory, monitory itd...
Zamiast przetwarzać.

Do autora wątku:
- polecałbym raczej rozwiązanie z procesami potomnymi, odpada część problemów
wątko-pochodnych

Jeśli jednak musisz wykorzystać wątki, istnieje coś takiego jak boost::thread_group. Metoda, której szukasz to join_all.

Poza tym, z tego co wiem, dla 10000 klientów nie musisz tworzyć 10000 wątków.
Możesz stworzyć 10. Jak to zrobić? Trzeba użyć właśnie "thread pool":

http://www.cs.wustl.edu/~schmidt/PDF/C++-report-col6.pdf

Jeśli to będzie za mało, to poszukaj czegoś o wzorcu "reactor".Piotr Likus edytował(a) ten post dnia 23.02.10 o godzinie 10:40
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: Zaczekać na zakończenie wątków

Piotr Likus:
Adam Woźniak:
Piotr P.:
[..] Wątki w aplikacji serwerowej nie pomogą Ci za bardzo z
wydajnością nawet jeśli masz 100 jednostek CPU. [..]

Yyyy... Możesz rozwinąć tę tezę? Bo trochę mnie ta teza
zadziwiła.

Wątki raczej pogarszają wydajność... Tracisz czas na semafory, monitory itd...
Zamiast przetwarzać.

Nie zgodzę się.
Jeśli przetwarzanie (obojętnie czy na wątkach czy na procesach) musi być jakoś synchronizowane, to synchronizacja pomiędzy wątkami jest lzejsza, niż synchronizacja pomiędzy procesami.
odpada część problemów wątko-pochodnych

Yyyy... Jakich problemów. Jesli przetwarzanie ma być jakoś synchronizowane, to znacznie łatwiej utrzymywać współdzielone struktury danych w ramach jednego procesu / jednej przestrzeni adresowej (i przetwarzać je wielowątkowe), niż przetwarzać to przy pomocy wielu procesów i komuniokować się np. przez pokraczne pamięci dzielone.

Pozdro, Adam Woźniak

PS.
Przyznaję, ze programowanie wielowątkowe jest trudniejsze niż programowanie wieloprocesowe.Adam Woźniak edytował(a) ten post dnia 23.02.10 o godzinie 11:01
Marek Dąbek

Marek Dąbek Software Engineer,
Intel Technology
Poland

Temat: Zaczekać na zakończenie wątków

Adam Woźniak:
Piotr Likus:
Adam Woźniak:
Piotr P.:
[..] Wątki w aplikacji serwerowej nie pomogą Ci za bardzo z
wydajnością nawet jeśli masz 100 jednostek CPU. [..]

Yyyy... Możesz rozwinąć tę tezę? Bo trochę mnie ta teza
zadziwiła.

Wątki raczej pogarszają wydajność... Tracisz czas na semafory, monitory itd...
Zamiast przetwarzać.

Nie zgodzę się.
Jeśli przetwarzanie (obojętnie czy na wątkach czy na procesach) musi być jakoś synchronizowane, to synchronizacja pomiędzy wątkami jest lzejsza, niż synchronizacja pomiędzy procesami.

Zgadzam się.
Do tego dodam, że jeśli wymagana jest duża ilość synchronizacji w stosunku do przetwarzania, to należy zastanowić się w ogóle nad sensownością przetwarzania równoległego. Prawa Amdahla się nie przeskoczy (można ale nie tak ;))

Jeśli chodzi o teorię dot. przetwarzania równoległego, to polecam artykuły Herba Suttera. Podaję link, w którym znajduje się spis tego co do tej pory opublikował:
http://herbsutter.wordpress.com/2010/01/17/effective-c...
L P

L P podskala.net

Temat: Zaczekać na zakończenie wątków

W zależności od potrzeb oczywiście - możesz wykorzystać swoją wersję (czyli zwyczajną współbieżność wątkową - każdy klient to nowy wątek). Możesz też zrobić współbieżność wyprzedzającą procesową ale to zależy od zadania (potrzeb). Nie chcesz przewozić jabłka z sadu Bentley'em - nie ? :)

Najpierw proponuje zrobic to bardzo prosto. Poźniej skalować - jak już działa i się sprawdza w życiu!

Jeśli to ma być w C zrobione i to Twoim sposobem z przykładu to dobrą opcją wydaje się być pooling wątków (tablica thraed_t**) synchronizowanych mutexem (o ile Twoje wątki używają jakichś wspolnych struktur/zmiennych, wspólnej pamięci).

Jeśli chcesz zliczać ilość wątków to możesz zrobić prosty licznik, który inkrementujesz / decrementujesz (synchronizowany) w trakcie działania programu.

Tak na szybko - prosty przykład z licznikiem (kilka zmian i może się wpasuje w Twoje potrzeby).


struct s_data {
...
};

int clients_cnt;

int
main(void)
{

clients_cnt = 0;
pthread_t thr_id;
struct s_data *data;

if ((data = malloc(sizeof(struct s_data)) == NULL)
return (1);

while(1) {
/* logika - ciało iteracyjne (Twój accept() np.)*/

/* synchronizowana inkrementacja */
clients_cnt++;

/* Tworzysz wątek */
pthread_create(thr_id, NULL, client_handler, (void *)data);
}

free(data);

return (0);
}

static void *
client_handler(void *data)
{
struct s_data *d = (struct s_data *)data;

pthread_detach(pthread_self());

/* logika - ciało funkcji */

/* synchronizowana dekrementacja */
clients_cnt--;

return (NULL);
}



Z pozdrowieniami,

ŁŁukasz Podkalicki edytował(a) ten post dnia 23.02.10 o godzinie 15:08
Marek Dąbek

Marek Dąbek Software Engineer,
Intel Technology
Poland

Temat: Zaczekać na zakończenie wątków



struct s_data {
...
};

int clients_cnt;

int
main(void)
{

clients_cnt = 0;
pthread_t thr_id;
struct s_data data = malloc(sizeof(struct s_data)); // co tam potrzebujesz

while(1) {
/* logika - ciało iteracyjne (Twój accept() np.)*/

/* inkrementujesz licznik */
clients_cnt++;
/* Tworzysz wątek */
pthread_create(thr_id, NULL, client_handler, (void *)data);
}

return (0);
}

static void *
client_handler(void *data)
{
struct s_data *d = (struct s_data *)data;

pthread_detach(pthread_self());

/* logika - ciało funkcji */

/* synchronizacja i.. */
clients_cnt--;

return (NULL);
}



1. struct s_data* data = malloc(sizeof(struct s_data))
2. if (data == NULL) goto error;
3. Wyciek pamięci ;) zabrakło free(data);
4. Warto to napisać wprost, bo to jeden z ważniejszych punktów:

/* pobierz mutex */
clients_cnt--;
/* oddaj mutex */
L P

L P podskala.net

Temat: Zaczekać na zakończenie wątków

Marek Dąbek:

1. struct s_data* data = malloc(sizeof(struct s_data))
2. if (data == NULL) goto error;
3. Wyciek pamięci ;) zabrakło free(data);
4. Warto to napisać wprost, bo to jeden z ważniejszych punktów:

/* pobierz mutex */
clients_cnt--;
/* oddaj mutex */

Racja! :))

PozdrawiamŁukasz Podkalicki edytował(a) ten post dnia 23.02.10 o godzinie 15:08
Piotr P.

Piotr P. Software Developer

Temat: Zaczekać na zakończenie wątków

Adam Woźniak:
[..] Wątki w aplikacji serwerowej nie pomogą Ci za bardzo z wydajnością nawet jeśli masz 100 jednostek CPU. [..]

Yyyy... Możesz rozwinąć tę tezę? Bo trochę mnie ta teza zadziwiła.

100 wątków w ramach jednego procesu, w dalszym ciągu jest jednym procesem. Jednym procesem zajmuje sie jedna jednostka CPU. Jeśli chcesz wykorzystać w pełni moc dzisiejszych procesorów to nie ma innego rozwiązania jak tworzenie procesow potomnych. Banalny przykład: Firefox VS Google Chrome.
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: Zaczekać na zakończenie wątków

Piotr P.:
[..] Jednym procesem zajmuje sie jedna jednostka CPU. [..]

Nie.
Piotr P.

Piotr P. Software Developer

Temat: Zaczekać na zakończenie wątków

Adam Woźniak:
Wątki raczej pogarszają wydajność... Tracisz czas na semafory, monitory itd...
Zamiast przetwarzać.

Nie zgodzę się.
Jeśli przetwarzanie (obojętnie czy na wątkach czy na procesach) musi być jakoś synchronizowane, to synchronizacja pomiędzy wątkami jest lzejsza, niż synchronizacja pomiędzy procesami.

A co chcesz synchronizować w tym konkretnym przypadku? Nawet jeśli musisz to zwykłe sygnały emitowane z obiektów zainicjowanych w procesie nadrzędnym i potomnym mogłyby rozwiązać problem komunikacji pomiędzy danymi różnych procesów. Inna sprawa, że równie dobrze proces potomny może kontaktować się z osobną aplikacją (demonem/serwisem). To rozwiązanie mogłoby być nawet lepsze bo tworzysz dwie warstwy: komunikacji z klientem i przetwarzania danych. I w pełni wykorzystujesz moc dzisiejszych procesorów.
Piotr P.

Piotr P. Software Developer

Temat: Zaczekać na zakończenie wątków

Adam Woźniak:
Piotr P.:
[..] Jednym procesem zajmuje sie jedna jednostka CPU. [..]

Nie.

Według jakiego standardu?
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: Zaczekać na zakończenie wątków

Piotr P.:
A co chcesz synchronizować w tym konkretnym przypadku? Nawet jeśli musisz to zwykłe sygnały emitowane z obiektów zainicjowanych w procesie nadrzędnym i potomnym mogłyby rozwiązać problem komunikacji pomiędzy danymi różnych procesów. Inna sprawa, że równie dobrze proces potomny może kontaktować się z osobną aplikacją (demonem/serwisem). To rozwiązanie mogłoby być nawet lepsze bo tworzysz dwie warstwy: komunikacji z klientem i przetwarzania danych. I w pełni wykorzystujesz moc dzisiejszych procesorów.

Mam na myśli ogólnie pojęta synchronizacje / komunikacje pomiędzy procesami.
Za pomocą sygnałów uniksowych wiele informacji nie przekażę. Miałem na myśli bardziej (niż sygnały) wyrafinowaną komunikację i synchronizację pomiędzy procesami czy wątkami (tu nie ma to wiekszego znaczenia).
L P

L P podskala.net

Temat: Zaczekać na zakończenie wątków

Adam Woźniak:
Piotr P.:
[..] Jednym procesem zajmuje sie jedna jednostka CPU. [..]

Nie.

Jeden proces w danym czasie obsługiwany jest przez jeden procesor - może mnie ominęła jakaś nowinka technologiczna ? :))
Adam Woźniak

Adam Woźniak software architect
and developer

Temat: Zaczekać na zakończenie wątków

Piotr P.:
Adam Woźniak:
Piotr P.:
[..] Jednym procesem zajmuje sie jedna jednostka CPU. [..]

Nie.

Według jakiego standardu?

Napisze tak: nie znam komputerów, na których wątki pojedynczego procesu musiałyby być wykonywane na nie więcej niż jednym CPU.

Można ograniczyć proces, aby jego wątki nie działały na więcej niż N core'ach (np. windowsowy mechanizm affinity mask), ale zgaduję, że nie to masz na myśli.

Pozdrawiam, Adam Woźniak

Następna dyskusja:

pthread_create - maksymalna...




Wyślij zaproszenie do