Forum Linux.pl

Programowanie => C/C++ => Wątek zaczęty przez: janiszp w 2007-12-29, 15:42:51

Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 15:42:51
Witam,
napisałem prosty program w C wykorzystujący wątki, jego kod znajduje się pod adresem:
http://student.agh.edu.pl/~janisz/cos.c

W tym programie tworzę 10 wątków, każdy wątek wypisuje na ekran tekst i anuluje pozostałe wątki. Problem polega na tym, że czasem program dostaje sygnał SIGSEGV, z tego co udało mi się wywnioskować dzieje sie tak wtedy, gdy wątek wywołuje funkcję pthread_cancel() dla wątku, który już zakończył działanie.
Według http://www.opengroup.org/onlinepubs/007908775/xsh/pthread_cancel.html funkcja pthread_cancel powinna zwrócić błąd ESRCH jeżeli nie ma wątku o podanym ID.


program testowałem na:
ubuntu 7.10 (2.6.22) z glibc 2.6.1
gentoo 4.1.1(2.6.20) z glibc 2.5

program działa poprawnie na Solarisie

Czy ktoś wie, w czym może tkwić problem?
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: chmooreck w 2007-12-29, 16:55:45
próbowałeś to odpalić pod gdb ?
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 17:14:16
tak, właśnie dzięki gdb wywnioskowałem, że program dostaje SIGSEGV gdy wywołuje pthread_cancel
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 17:21:50
A mnie ten program działa - tak mi się przynajmniej wydaje - jaki jest prawidłowy wynik?

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 17:31:23
powinno wypisać 10 razy "ble" :),
problem w tym, że on nie zawsze się wykrzacza - u mnie mniej więcej co 10 uruchomień, im więcej wątków tym częściej
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 17:33:22
Zobacz czy przypadkiem nie tworzą się procesy zombie.

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 17:34:28
Czy jak liczba wątków będzie mniejsza np 5 to ten problem też się pojawia ?

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 17:38:00
Zastanawiam się czy to nie jest wina tego, że główny proces skończy się szybciej niż wątki? Może daj jakieś uśpienie po uruchomieniu wątków?

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 17:43:47
główny proces nie kończy się szybciej bo synchronizuje się za pomocą pthread_join,
dla 5 wątków nie dostaje SIGSEGV, sprawdzę jeszcze co z zombiakami

EDIT
zombie, się nie tworzą, ale jeśli wątek główny kończy działanie wcześniej, to reszta wątków też kończy działanie (jeżeli są dołączalne, a domyślnie są)
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 17:48:13
Z strace widać że w pewnym momencie dziecku brakuje rodzica. Głupio brzmi ale chyba system nie radzi sobie z ich obsługą.

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 17:52:46
Jak dodałem sleep(1) do każdej pętli for to działa dobrze.

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 18:02:44
u mnie raczej wszystkie wątki mają rodzica (chyba, że można jeszcze z jakąś inną opcją strace uruchomić :) )

strace -e trace=process ./cos
execve("./cos", ["./cos"], [/* 33 vars */]) = 0
clone(child_stack=0xb7e614c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb7e61bd8, {entry_number:6, base_addr:0xb7e61b90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb7e61bd8) = 13883
clone(child_stack=0xb76604c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb7660bd8, {entry_number:6, base_addr:0xb7660b90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb7660bd8) = 13884
clone(child_stack=0xb6e5f4c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb6e5fbd8, {entry_number:6, base_addr:0xb6e5fb90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb6e5fbd8) = 13885
clone(child_stack=0xb665e4c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb665ebd8, {entry_number:6, base_addr:0xb665eb90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb665ebd8) = 13886
clone(child_stack=0xb5e5d4c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb5e5dbd8, {entry_number:6, base_addr:0xb5e5db90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb5e5dbd8) = 13887
ble
clone(child_stack=0xb565c4c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb565cbd8, {entry_number:6, base_addr:0xb565cb90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb565cbd8) = 13888
clone(child_stack=0xb4e5b4c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb4e5bbd8, {entry_number:6, base_addr:0xb4e5bb90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb4e5bbd8) = 13889
clone(child_stack=0xb465a4c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb465abd8, {entry_number:6, base_addr:0xb465ab90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb465abd8) = 13890
clone(child_stack=0xb3e594c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb3e59bd8, {entry_number:6, base_addr:0xb3e59b90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb3e59bd8) = 13891
clone(child_stack=0xb36584c4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb3658bd8, {entry_number:6, base_addr:0xb3658b90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1ble
ble
ble
ble
ble
+++ killed by SIGSEGV (core dumped) +++
Process 13882 detached
}, child_tidptr=0xb3658bd8) = 13892
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: chmooreck w 2007-12-29, 18:08:24
proszę was: używajcie opcji edycji, bo się to potem źle czyta....
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 18:12:51
Dziwne jest to, że masz core dumped. Analiza gdb pewnie wiele by powiedziała. Jak dla mnie to się po prostu za szybko dzieje i gubi się na synchronizacji :( Ale czemu to nie mam pojęcia. Albo brak wiedzy albo błąd w jądrze. Nie masz gdzieś pod ręką najnowszego ;)

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 18:26:24
Zastanawiam się też czy nie powinieneś jednak anulować tych wątków z funkcji nadrzędnej i czy nie powinieneś zwrócić czegoś innego niż NULL.

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 18:33:52
W gdb uruchamiałem to już kilkanaście razy, na jądrze 2.6.23 też sprawdzałem i też się krzaczy. Właściwie to siedzę nad tym problemem kilka dni i nie mogę dojść do tego. Może za dużo wątków rzeczywiście, bo ten program to raczej dla celów edukacyjnych napisałem. Czytałem gdzieś że Native Posix Thread Library nie jest do końca zgodne z posix, więc może tutaj jest właśnie niezgodne

EDIT
Nie, ponieważ w poleceniu (to jest moje "zadanie domowe" z systemów operacyjnych) jest napisane, że wątek po zakończeniu działania ma anulować pozostałe, a poza tym nigdzie nie jest napisane, że wątki można anulować tylko z wątku nadrzędnego :)

EDIT
można zwracać NULL, w przykładach w różnych książkach tak jest
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 18:52:55
A jak bardzo solaris zgodny jest z POSIX?

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 19:31:07
w sumie to nie wiem :), w każdym razie tam działa. Jeszcze jedna obserwacja - w Solarisie tid moich wątków są małymi liczbami - 1, 2, 3 ... Natomiast w Linuxie są to duże liczby np. 3084835728. Przeglądałem kod funkcji pthread_cancel() i okazało się, że TID wątków w Linuxie jest wskaźnikiem do struktury opisującej wątek, i tam są odwołania do pól tej struktury.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 19:32:30
Dziwne jest to, że jak doda się funkcję sleep to wszystko ładnie działa. Może jakaś dodatkowa synchronizacja?

M.
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: janiszp w 2007-12-29, 19:43:35
a gdzie dodałeś sleep?
bawiłem się już synchronizacją mutexami - zrobiłem tak, że tylko jeden wątek na raz mógł odwoływać się do tablicy thread_tab (w której trzymam TID'y). Główny wątek najpierw blokował mutex, uruchamiał wszystkie wątki, następnie go zwalniał. Pozostałe wątki podobnie - blokowały mutex, anulowały wszystkie wątki i zwalniały go. Wtedy program dostawał SIGSEGV, gdy główny wątek wywoływał pthread_join() :-)
Tytuł: [C] problem z wątkami (pthread_cancel)
Wiadomość wysłana przez: w 2007-12-29, 19:48:45
#include 
#include
#include

#define THREAD_NUM 10

int thread_num = THREAD_NUM;
pthread_t thread_tab[THREAD_NUM];

void* run(void* arg)
{
        int i;
        pthread_t self;

        printf("ble\\n");
        self = pthread_self();
        for (i = 0; i < THREAD_NUM; i++)
                if (thread_tab[i] && !pthread_equal(self, thread_tab[i]))
                  pthread_cancel(thread_tab[i]);
        return NULL;
}

int main(void)
{
        int i;

        for (i = 0; i < THREAD_NUM; i++){
                thread_tab[i] = 0;
}
        for (i = 0; i < THREAD_NUM; i++){
                pthread_create(&thread_tab[i], NULL, run, NULL);
sleep(1);
        }
        for (i = 0; i < THREAD_NUM; i++){
                pthread_join(thread_tab[i], NULL);
sleep(1);
        }

        return 0;
}