Здравствуйте.Мой уровень программирования невысокий. Хочу разобраться с потоками. Если бы вы могли мне помочь понять почему у меня прога валиться в кору, буду безмерно вам благодарен.
И так коротко о программе. Программа слушает UDP сокет. При получении датаграмы, создается поток, в потоке создаются собственные данные, поток отсоеденяется и дальше идет работа с mysql, после чего функция потока завершается (соответственно вызываются деструкторы для уничтожения собственных даных потока.) Так вот кора получается то после 2 полученых пакетов, то после 20, то после 10, причем абсолютно в разных местах. Причем никакой коры нет если закоментировать запись в mysql. Выходит проблема именно когда идет взаимодействие с базой. дискриптор базы в начале у меня был объявлен глобально и любая функция могла вызвать запросы. Такой вариант тоже выпадал в кору, поэтому я решил дискриптор тоже сделать собственными данными потока. Результат - кора. Вот выдержки исходника.typedef struct mysql_thread
{
char query[BUF_SIZE];
char *separator,*ip,*url;
MYSQL mysqld;
}mysql_thread_data;pthread_key_t rl_key;
pthread_once_t rl_once = PTHREAD_ONCE_INIT;void init_DB(MYSQL *mysql_thread)
{
if (!(mysql_real_connect(mysql_thread,setST.DBhost,setST.DBlogin,setST.DBpass,setST.DB,setST.port,setST.MySQLsock,2)))
{
syslog(LOG_NOTICE,"ERROR: Can not connect to mysql database.");
exit(EXIT_FAILURE);
}
if (mysql_select_db(mysql_thread,setST.DB))
{
syslog(LOG_NOTICE,"ERROR: Can not select database.");
exit(EXIT_FAILURE);
}
}void close_DB (MYSQL *mid)
{
mysql_free_result(res);
mysql_close(mid);
}
static void insert_DB (void * arg)
{mysql_thread_data *mysql_insert_var;
зthread_once(&rl_once,dos_mysql_once_th);
if ((mysql_insert_var=pthread_getspecific(rl_key)) == NULL )
{
mysql_insert_var = calloc(1,sizeof(mysql_insert_var));
pthread_setspecific(rl_key,mysql_insert_var);
}
pthread_detach(pthread_self());
init_DB(&mysql_insert_var->mysqld);
close_DB(&mysql_insert_var->mysqld);
}
......
pthread_create(&tid,NULL,(void *)&insert_DB,(void *) msg);в данном куске я оставил только конект к базе и закрытие базы и всеравно кора.
Код полностью рабочий, при компиляции ни ворнингов ни ероров.У меня только одно предположение - я неправильно организовываю собственные данные потока.
Наставьте на пусть истинный.Спасибо.
вот такой эксперимент я провел. после
pthread_detach(pthread_self());
printf ("thread %d\n",mysql_insert_var);просто распечатываю указатель.
так вот
thread 674513532
thread 674513532
thread 674513532
thread 674514036
thread 674514540
thread 674515044первые 3 указателя одинаковые.
значит получается что 3 потока используют один и те же данные. В том числе и дискриптор мускуля. А не из-за этого ли кора?
Коллега, а чем был обусловлен выбор C-подобных языков для работы с тредами и сетевыми вещами? Просто работа с указателями та ещё пестня...если честно. Никогда нельзя быть в итоге уверенным что где-то нет утечки :(Моё скромное ИМХО, если нужно работать с потоками и разбирать UDP - по посмотрите в сторону Python/Twisted - как вариант или Erlang тоже отлично подойдёт.
> Коллега, а чем был обусловлен выбор C-подобных языков для работы с тредами
> и сетевыми вещами? Просто работа с указателями та ещё пестня...если честно.
> Никогда нельзя быть в итоге уверенным что где-то нет утечки :(
> Моё скромное ИМХО, если нужно работать с потоками и разбирать UDP -
> по посмотрите в сторону Python/Twisted - как вариант или Erlang тоже
> отлично подойдёт.Знаю чуть-чуть С поэтому выбрал именно его.
Как я и предоплогал разные потоки обращаются к одним данным
printf ("thread %d-%d\n",mysql_insert_var,pthread_self());
через pthread_self() я получаю идентификатор потока. Они разные :(thread 674513532-674328896
thread 674513532-674328256
thread 674513532-674327936
thread 674513532-674327616подскажите в чем косяк и как исправить.
> Как я и предоплогал разные потоки обращаются к одним данным
> подскажите в чем косяк и как исправить.Нужен ГОЛ!!! Нужен ГОЛ!!! Нужен ГОЛ!!!.... Тфу,
Нужен МУТЕХ !!!Нужен МУТЕХ !!!Нужен МУТЕХ !!!
>> Как я и предоплогал разные потоки обращаются к одним данным
>> подскажите в чем косяк и как исправить.
> Нужен ГОЛ!!! Нужен ГОЛ!!! Нужен ГОЛ!!!.... Тфу,
> Нужен МУТЕХ !!!Нужен МУТЕХ !!!Нужен МУТЕХ !!!минуточку.
мутех приведет к тому что только один потом будет работать все остальные ожидать.
я же хотел что бы все делалось параллельно.
Ведь есть же такое понятие как thread-specific data - есть. есть способ ее реализовать - есть. Ну так причем тут мутекс? Ведь только первые несколько записей лажанутые остальыне нормальные. Думаю без мутекса тут можно обойтись. Вопрос что я сделал неправильно.
>>> Как я и предоплогал разные потоки обращаются к одним данным
>>> подскажите в чем косяк и как исправить.
>> Нужен ГОЛ!!! Нужен ГОЛ!!! Нужен ГОЛ!!!.... Тфу,
>> Нужен МУТЕХ !!!Нужен МУТЕХ !!!Нужен МУТЕХ !!!
> минуточку.
> мутех приведет к тому что только один потом будет работать все остальные
> ожидать.1. можно юзать pthread_rwlock
2. Где функция dos_mysql_once_th(), и pthread_key_create()
3. pthread_self() возвращает pthread_t он же long, спецификатор для printf - %ld
Ну и самое интересное - при обращении по одному разделяемому ключу, разные потоки будут получать доступ к разным данным.Прям уж так нужна pthread_setspecific() ???
Вариантов много, нужен весь код иль упрощённая версия, а так можно гадать долго.
Кстати, скорее всего команда pthread_setspecific(rl_key,mysql_insert_var);
меняет не одну и туже переменную rl_key, а уже свою :)
> 1. можно юзать pthread_rwlockнасколько я понимаю, тогда мне прийдется где-то хранить данные которые приходят по UDP. Так как буфер для них будет блокироваться длязаписи, а ведь это UDP, там никто ждать не будет - не збарл датаграму она пропала.
> 2. Где функция dos_mysql_once_th(), и pthread_key_create()
static void dos_mysql_th_destructor (void *ptr)
{
free(ptr);
}static void dos_mysql_once_th (void)
{
pthread_key_create(&rl_key,dos_mysql_th_destructor);
}> 3. pthread_self() возвращает pthread_t он же long, спецификатор для printf - %ld
от этого ничего не изменилось. вывод остался прежним. но спасибо за информацию.
> Ну и самое интересное - при обращении по одному разделяемому ключу, разные
> потоки будут получать доступ к разным данным.тут не понял.
> Прям уж так нужна pthread_setspecific() ???
> Вариантов много, нужен весь код иль упрощённая версия, а так можно гадать
> долго.насколько я понял pthread_setspecific() это ключевая команда. без нее не будет своих даных у каждого потока.
> Кстати, скорее всего команда pthread_setspecific(rl_key,mysql_insert_var);
> меняет не одну и туже переменную rl_key, а уже свою :)маловероятно. rl_key объявлена как глобальная. а потоки разделяют между собой все глобальные переменные процесса.
>> 1. можно юзать pthread_rwlock
> насколько я понимаю, тогда мне прийдется где-то хранить данные которые приходят по
> UDP. Так как буфер для них будет блокироваться длязаписи, а ведь
> это UDP, там никто ждать не будет - не збарл датаграму
> она пропала.А нафига тогда многотредовость? :)
Ну ладно, две нити - одна слушает UDP другая пишет в SQL
>>> 1. можно юзать pthread_rwlock
>> насколько я понимаю, тогда мне прийдется где-то хранить данные которые приходят по
>> UDP. Так как буфер для них будет блокироваться длязаписи, а ведь
>> это UDP, там никто ждать не будет - не збарл датаграму
>> она пропала.
> А нафига тогда многотредовость? :)потому что датаграмы валяться огромным потоком.
что бы обойтись без потерь решил сделать ставку на потоки. поток получил датаграму и дальше себе пишет в мускуль, параллельно висят еще несколько потоков и делают тоже самое. Главное максимально быстро забрать датаграму что бы не потерять.ну а с другой стороны. да пофигу UDP или еще что-то другое, вот у меня не работает - хочу разобраться.
>[оверквотинг удален]
>>> насколько я понимаю, тогда мне прийдется где-то хранить данные которые приходят по
>>> UDP. Так как буфер для них будет блокироваться длязаписи, а ведь
>>> это UDP, там никто ждать не будет - не збарл датаграму
>>> она пропала.
>> А нафига тогда многотредовость? :)
> потому что датаграмы валяться огромным потоком.
> что бы обойтись без потерь решил сделать ставку на потоки. поток получил
> датаграму и дальше себе пишет в мускуль, параллельно висят еще несколько
> потоков и делают тоже самое. Главное максимально быстро забрать датаграму что
> бы не потерять.Ну ладно, дело ваше... Тока не пойму, как можно из одного сокета читать параллельно.
> ну а с другой стороны. да пофигу UDP или еще что-то другое,
> вот у меня не работает - хочу разобраться.Дай всю коду, или упрощенный вариант.
Всё же pthread_key_t редкостный вариант. :)
ЁЙо...static pthread_key_t rl_key;
static pthread_once_t rl_once = PTHREAD_ONCE_INIT;
> ЁЙо...
> static pthread_key_t rl_key;
> static pthread_once_t rl_once = PTHREAD_ONCE_INIT;ничего это не изменило :(
но зато я выяснил что и мускуля это не имеет отношение. Кора получается просто доступе к mysql_insert_var из функции insert_DB.
Что-то я намутил одно значно.
Используйте __thread вместо работы с pthread key, весьма облегчает.http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html
Ну а вообще без исходного кода трудно судить.
> Используйте __thread вместо работы с pthread key, весьма облегчает.
> http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html
> Ну а вообще без исходного кода трудно судить.Мне очень жаль но мой уровень не позволят пока оценить все преимущества __thread.
Завтра попробую сделать облегченный код без лабуды с UDP, что бы и самому было проще понять что к чему.
>> Используйте __thread вместо работы с pthread key, весьма облегчает.
>> http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html
>> Ну а вообще без исходного кода трудно судить.
> Мне очень жаль но мой уровень не позволят пока оценить все преимущества
> __thread.
> Завтра попробую сделать облегченный код без лабуды с UDP, что бы и
> самому было проще понять что к чему.Кора из-за pthread_detach(pthread_self());
>>> Используйте __thread вместо работы с pthread key, весьма облегчает.
>>> http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html
>>> Ну а вообще без исходного кода трудно судить.
>> Мне очень жаль но мой уровень не позволят пока оценить все преимущества
>> __thread.
>> Завтра попробую сделать облегченный код без лабуды с UDP, что бы и
>> самому было проще понять что к чему.
> Кора из-за pthread_detach(pthread_self());нет. я пробовал и без него. Добавлял pthread_join. Всеравно кора. Сегодня сделаю упрощенный вид программки только с потоками, а там будет видно. Дело в том что потоки программирую первый раз. Да и вообще программирую после перерыва лет 10 наверное. Так что всякие тупости это не случайность,а мой стиль программирования :)
> всякие тупости это не случайность,а мой стиль программирования :)На bash.org срочно! :)
>[оверквотинг удален]
> так вот
> thread 674513532
> thread 674513532
> thread 674513532
> thread 674514036
> thread 674514540
> thread 674515044
> первые 3 указателя одинаковые.
> значит получается что 3 потока используют один и те же данные. В
> том числе и дискриптор мускуля. А не из-за этого ли кора?Короча скажи спасибо писателям glibc и ядра.
Добавь в функцию нити sleep(10); и посмотри на указатели приватных данных :)
----
Вот так без sleep();НОМЕР pthread_self() адрес структуры
----------------------------------------------
Thread[0]: 140737346094848 @ address[0x6054c0]
Thread[2]: 140737329309440 @ address[0x603180]
Thread[3]: 140737320916736 @ address[0x603b20]
Thread[4]: 140737310336768 @ address[0x603a30]
Thread[5]: 140737301944064 @ address[0x603a50]
Thread[1]: 140737337702144 @ address[0x603160]
Thread[6]: 140737293551360 @ address[0x603160]
Thread[7]: 140737346094848 @ address[0x603160]
Thread[8]: 140737346094848 @ address[0x603160]а вот так со sleep(10)
Thread[0]: 140390059624192 @ address[0x60d4c0]
Thread[1]: 140390051231488 @ address[0x60b250]
Thread[2]: 140390042838784 @ address[0x60b290]
Thread[4]: 140390026053376 @ address[0x60b3d0]
Thread[6]: 140390017660672 @ address[0x60b650]
Thread[3]: 140390034446080 @ address[0x60b270]
Thread[5]: 140389883442944 @ address[0x60b510]
Thread[7]: 140390009267968 @ address[0x60b9a0]
Thread[8]: 140389931546368 @ address[0x60bae0]
Thread[9]: 140389923153664 @ address[0x60b670]
> Добавь в функцию нити sleep(10); и посмотри на указатели приватных данных :)делал я это уже.
действительно с адресацией ситуация исправилась, но кора не пропала.
mysql_init и
mysql_thread_init
Как оказалось проблем неколько с этой корой.
Первая как и предпологалось при доступе к мускулю. А вот вторая... Я парсил строки. Использовал strtok. И вот он, зараза, делал мне кору. Переписал парс на указателях, тоесть ищу символ смещаю указатели присваиваю и т.д. И эта кора пропала. Но с мускулем проблема так и осталась. На сайте мускуля написаноThe thread-safe client library, libmysqlclient_r, is thread-safe per connection. You can let two threads share the same connection with the following caveats:
...
If you want to use multiple threads on the same connection, you must have a mutex lock around your pair of mysql_query() and mysql_store_result() calls. Once mysql_store_result() is ready, the lock can be released and other threads may query the same connection.
....ключевое слово on the same connection. Дискриптов мускуля я сделал собственонстью потока. И каждый поток у меня открывает отедльный конект к мускулю. Но кора от этого не пропала. На сайте мускуля рекомендуют использовать мутекс. Видимо прийдется последовать их совету.
>[оверквотинг удален]
> ...
> If you want to use multiple threads on the same connection, you
> must have a mutex lock around your pair of mysql_query() and
> mysql_store_result() calls. Once mysql_store_result() is ready, the lock can be released
> and other threads may query the same connection.
> ....
> ключевое слово on the same connection. Дискриптов мускуля я сделал собственонстью потока.
> И каждый поток у меня открывает отедльный конект к мускулю. Но
> кора от этого не пропала. На сайте мускуля рекомендуют использовать мутекс.
> Видимо прийдется последовать их совету.в многопоточных приложениях вместо strtok настоятельно рекомендуется пользовать реентрантную strtok_r(). man strtok_r() вам в помощь и не изобретайте велосипеды=)
я уже вставал на эти грабли с strtok() и прочими не реентрантыми функциями в многопоточке.
> На сайте мускуля рекомендуют использовать мутекс.
> Видимо прийдется последовать их совету.https://www.opennet.ru/openforum/vsluhforumID9/9057.html#4
=)
>> На сайте мускуля рекомендуют использовать мутекс.
>> Видимо прийдется последовать их совету.
> https://www.opennet.ru/openforum/vsluhforumID9/9057.html#4
> =)совет неверный.
>>> На сайте мускуля рекомендуют использовать мутекс.
>>> Видимо прийдется последовать их совету.
>> https://www.opennet.ru/openforum/vsluhforumID9/9057.html#4
>> =)
> совет неверный.Нет такой функции.
> Наставьте на пусть истинный.Посмотрите внимательно на свой код:
---
mysql_thread_data *mysql_insert_var;mysql_insert_var = calloc(1,sizeof(mysql_insert_var));
---ЗЫ: Вова вам правильно говорит, используйте __thread