Переменная обнуляется "сама по себе"

Модератор: Модераторы разделов

Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Переменная обнуляется "сама по себе"

Сообщение RasenHerz »

Пишу небольшой сервер, каждое соединение в котором обрабатывается разными потоками. Каждый вновь созданный поток добавляется в двунаправленный список активных соединений; отработавшие потоки удаляют себя из списка активных и перемещают в список неактивных. В определенный момент времени основной поток решает очистить список неактивных соединений и освободить занимаемую память,Эту работу выполняет следующий код:

Код: Выделить всё

void clear_list(void *arg, int kill_threads){
    if (!arg)
        return;
    ClientList *list = (ClientList*)arg;
    if (!IS_EMPTY_LIST(list)){
        pthread_mutex_lock(&list->lock);

        ClientList *elem;
        int ret = 0;

        //Cleaning all resources used by threads
        //FIXME: ??? after processing 1 element, list becomes 0x0
        for (elem = list->next; elem != list; elem = elem->next){ //Перебираем все элементы списка, переменная list является головой списка, поэтому ее не трогаем
            if (pthread_join(*elem->client->thr, (void**) & ret) != 0) //После вызова переменная list обнуляется
                perror("pthread_join");
            else {
                printf("[0x%x]: Exited with %i code.\n"
                        , elem->client->thr, (int) (long) ret);
                if (kill_threads)
                    pthread_cancel(*elem->client->thr);
                free(elem->client->thr);
                if (elem->client->file)
                    free(elem->client->file);
            }
        }
        ..............
    }
}

Проверил отладчиком, оказалось что переменная list обнуляется после вызова pthread_join().
Вот структуры ClientList и Client:

Код: Выделить всё

struct Client {
        int sd;
        int connected;
        int logged;
        char *file;
        int fd;
        off_t offset;
        unsigned int flen;
        void *data;
        pthread_t *thr;
    };

    struct ClientList {
        pthread_mutex_t lock;
        Client *client;
        ClientList *next;
        ClientList *prev;
    };

Если в место list использовать ((ClientList*)arg), то все отрабатывает на ура. Не пойму в чем дело...

P.S.

Код: Выделить всё

negativ@negativ-zet:~$ g++ --version
g++ (GCC) 4.4.0
Copyright (C) 2009 Free Software Foundation, Inc.

negativ@negativ-zet:~$ uname -a
Linux negativ-zet 2.6.29.1 #3 SMP Wed Apr 22 03:43:52 MSD 2009 x86_64 GNU/Linux

negativ@negativ-zet:~$ gdb --version
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Переменная обнуляется "сама по себе"

Сообщение NickLion »

Пока причины непонятны. Вот только момент хочется уточнить:

Код: Выделить всё

int ret = 0;
...
if (pthread_join(*elem->client->thr, (void**) & ret) != 0)

Под 64-битной платформой могут быть проблемы из-за sizeof(int)=4, sizeof(void*)=8.

PS поправил, заметил, что все-таки 64 бит
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Переменная обнуляется "сама по себе"

Сообщение RasenHerz »

не знаю даже что делать, баг пытаюсь отловить весь день; пока обойдусь грязным хаком,

P.S. грешу на новый gcc, т.к. он уже пару раз меня подводил:

Код: Выделить всё

while (bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT) <= 0);

после удачного чтения данных с сокета он оставлял переменную bytes равной нулю, а из цикла while выходил(!!!). то ли разработчики компилятора ужесточили правила игры, то ли я что-то подзабыл и компилятор должен был сначала выполнить присваивание, а потом сравнение.
пришлось изменить код на следующий:

Код: Выделить всё

while (bytes <= 0){
            bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT);
}
Спасибо сказали:
Аватара пользователя
klark
Сообщения: 194
ОС: Gentoo Linux

Re: Переменная обнуляется "сама по себе"

Сообщение klark »

RasenHerz писал(а):
17.05.2009 19:21
Каждый вновь созданный поток добавляется в двунаправленный список активных соединений; отработавшие потоки удаляют себя из списка активных и перемещают в список неактивных.

А можно сделать так, чтобы только менеджер потоков работал с двунаправленными списками? Впрочем, если при работе с мьютексами всё равно возникают коллизии, надо смотреть весь код, особенно инициализацию дочернего потока.
Лечите катаракту у офтальмолога, а мне очки не втирайте!
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Переменная обнуляется "сама по себе"

Сообщение RasenHerz »

klark писал(а):
18.05.2009 01:53
А можно сделать так, чтобы только менеджер потоков работал с двунаправленными списками? Впрочем, если при работе с мьютексами всё равно возникают коллизии, надо смотреть весь код, особенно инициализацию дочернего потока.

Любое обращение к списку производится только после запирания мьютекса. Как я уже говорил, основная задача главного потока - слушать определенный порт, при наличии соединения - создать новые структуры ClientList и Client, инициализировать их должным образом и создать новый поток, которому будут переданы в качестве аргумента ClientList и Client. все остальное делает новый поток - добавляет себя в список активных, передает/получает данные, перемещает себя в список неактивных и завершается. Никаких коллизий возникнуть не может принципиально - каждый кусок для работы с списками выполняется только в одном потоке.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Переменная обнуляется "сама по себе"

Сообщение drBatty »

RasenHerz писал(а):
18.05.2009 00:44
после удачного чтения данных с сокета он оставлял переменную bytes равной нулю, а из цикла while выходил(!!!). то ли разработчики компилятора ужесточили правила игры, то ли я что-то подзабыл и компилятор должен был сначала выполнить присваивание, а потом сравнение.

я всегда писал
if((x = f()) <= 0)
т.к. был уверен, что приоритет = ниже чем сравнения, потому у вас должно выполнятся if(x = (f() <= 0)) т.е. переменная обнулится, и условие не выполнится. Странно что раньше всё работало. наверное у вас какие-то хитрые опции компилятора используются...
RasenHerz писал(а):
17.05.2009 19:21
Проверил отладчиком, оказалось что переменная list обнуляется после вызова pthread_join().

ну видимо эта функция и затирает. видимо затирает stack, в котором и лежит list.
((ClientList*)arg) лежит в другом месте(может и вобше не в стеке), потому с ней всё работает.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Переменная обнуляется "сама по себе"

Сообщение Женя Подсыпальников »

Можа, сделать класс списку
и, выставив в деструкторе брейк -
поглядеть "стирателю" "в глаза" ? :)

А то - увеличь стэк
ли подержи список в глобале,
для проверки переливу... :)
Пойдём на рыбалку !
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: Переменная обнуляется "сама по себе"

Сообщение NickLion »

Так Вы исправили

Код: Выделить всё

int ret = 0;
? Нужно 64-битный тип использовать, неизвестно куда еще 4 байта нулей будут записаны...
Спасибо сказали:
Аватара пользователя
Женя Подсыпальников
Сообщения: 482

Re: Переменная обнуляется "сама по себе"

Сообщение Женя Подсыпальников »

Ещё - можно попробывать перед "ret" -
звёздочку умножения выставить,

там ещё "равно нулю, мол" написано... :)

(джоинтова функция - аллокирует или обнуляет
разадресованный указатель на указатель...
Коли ты указатель передаёшь, а не указатель на указатель -
оно тебе по стэку протрёт.
А ты можешь вообще NULL вторым параметром передать...
Если нет - делай так:
void* ret = NULL;
joint(..., &ret));
if (ret) free(ret);
...
Но можешь и NULL вторым параметром передать...)
Пойдём на рыбалку !
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Переменная обнуляется "сама по себе"

Сообщение RasenHerz »

NickLion писал(а):
18.05.2009 12:10
Так Вы исправили

Код: Выделить всё

int ret = 0;
? Нужно 64-битный тип использовать, неизвестно куда еще 4 байта нулей будут записаны...

вы правы, завершил поток с кодом выхода 0x4141414141414141 и переменная list стала ссылаться на 0x41414141. во всем виновата моя невнимательность.
тред можно закрывать, всем спасибо за помощь.
Спасибо сказали:
Аватара пользователя
AestheteAnimus
Сообщения: 135
ОС: FreeBSD 8.0-RELEASE amd64

Re: Переменная обнуляется "сама по себе"

Сообщение AestheteAnimus »

RasenHerz писал(а):
18.05.2009 00:44

Код: Выделить всё

while (bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT) <= 0);

А вот что вы хотели добиться такой строчкой? Может Вы все-таки имели ввиду это:

Код: Выделить всё

while ( (bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT)) <= 0);
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: Переменная обнуляется "сама по себе"

Сообщение RasenHerz »

AestheteAnimus писал(а):
18.05.2009 20:37
RasenHerz писал(а):
18.05.2009 00:44

Код: Выделить всё

while (bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT) <= 0);

А вот что вы хотели добиться такой строчкой? Может Вы все-таки имели ввиду это:

Код: Выделить всё

while ( (bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT)) <= 0);


да, просто (bytes = recv(cl->sd, buffer, BLCK_SZ, MSG_DONTWAIT) раньше было обернуто в макрос (т.е. выражение было ограничено скобками) и все работало, потом я решил убрать макрос, но напрочь забыл о том, что приоритет присваивания ниже приоритета логического сравнения - от сюда и выплыла ошибка. каюсь, ошибка наиглупейшая. =)
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Переменная обнуляется "сама по себе"

Сообщение drBatty »

RasenHerz писал(а):
19.05.2009 02:21
от сюда и выплыла ошибка. каюсь, ошибка наиглупейшая. =)
угу... можно позлорадствовать... только я сам помню всю ночь такое искал в собственном коде :(
теперь ставлю такие скобки всегда...
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
кодировщик
Сообщения: 974
Статус: зарёган в пятницу 13
ОС: Linux

Re: Переменная обнуляется "сама по себе"

Сообщение кодировщик »

я тоже сам на такие грабли наступал, пока не обратил внимание, что везде идёт if((.....))!=NULL) or while((......))>0) etc
Спасибо сказали: