Если вкратце, многоуважаемый Олл, есть примерно такой кусов кода (см. ниже). Все вроде бы работает (пишем под линукс), но с с некоторых пор (с каких пор, к сожалению, выяснить не удалось -- произошел какой-то апдейт дебиана или что-то изменилось в нашем коде), стал ломаться вызов mysql_real_connect -- стал возвращать NULL некоторых тредах. При этом, если connect завершается успешно, то обычно первый же запрос говорит "server has gone away during query". Самое неприятное, что происходит это только если запустить программу под дебаггером -- при запуске без дебаггера все работает достаточно надежно.
При этом, если раскомментировать строку с usleep, то проблема исчезает — все опять начинает работать очень хорошо, как под дебаггером, так и без него. Такое решение, конечно, не устраивает, хочется докопаться до проблемы. Думал запостить баг в mysql, но решил сначала попросить коллективный разум посмотреть на этот код -- может быть чужие глаза лучше найдут проблему (или даже кто-то захочет поэкспериментировать на своей конфигурации).
У нас все работает на Debian Squeeze + Percona Server 5.5 (хотя, как я понимаю, сервер тут совершенно ни при чем). Компилировал как с библиотеками из поставки Percona, так и с теми, что идут в дебиане — разницы ровно никакой.
Спасибо всем
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
#include <mysql.h>
void* thread(void*)
{
my_bool mbRet = mysql_thread_init();
assert(mbRet == 0); // weird, but as per mysql_thread_init documentation
MYSQL sqlObj;
void* pRet = mysql_init(&sqlObj);
assert(pRet == &sqlObj);
pRet = mysql_real_connect(&sqlObj, "127.0.0.1", "root", "123", "mysql", 3306, "/var/run/mysqld/mysqld.sock", 0);
assert(pRet == &sqlObj); // ломается тут.
mysql_close(&sqlObj);
mysql_thread_end();
return NULL;
}
int main()
{
assert(mysql_thread_safe());
static const size_t nThreads = 10;
pthread_t threads[nThreads];
for (size_t i = 0; i < nThreads; ++i)
{
int iRet = pthread_create(&threads[i], NULL, thread, NULL);
//usleep(10000);
assert(iRet == 0);
}
for (size_t i = 0; i < nThreads; ++i)
{
void* retVal = NULL;
pthread_join(threads[i], &retVal);
assert(retVal == NULL);
}
return 0;
}
// compile: g++ a.cpp -ggdb -lpthread -lmysqlclient_r && gdb ./a.out
Здравствуйте, green.nsk, Вы писали:
GN>GN>#include <unistd.h>
GN>#include <pthread.h>
GN>#include <assert.h>
GN>#include <mysql.h>
GN>void* thread(void*)
GN>{
GN> my_bool mbRet = mysql_thread_init();
GN> assert(mbRet == 0); // weird, but as per mysql_thread_init documentation
GN> MYSQL sqlObj;
GN> void* pRet = mysql_init(&sqlObj);
GN> assert(pRet == &sqlObj);
GN> pRet = mysql_real_connect(&sqlObj, "127.0.0.1", "root", "123", "mysql", 3306, "/var/run/mysqld/mysqld.sock", 0);
GN> assert(pRet == &sqlObj); // ломается тут.
GN> mysql_close(&sqlObj);
GN> mysql_thread_end();
GN> return NULL;
GN>}
GN>int main()
GN>{
GN> assert(mysql_thread_safe());
GN> static const size_t nThreads = 10;
GN> pthread_t threads[nThreads];
GN> for (size_t i = 0; i < nThreads; ++i)
GN> {
GN> int iRet = pthread_create(&threads[i], NULL, thread, NULL);
GN> //usleep(10000);
GN> assert(iRet == 0);
GN> }
GN> for (size_t i = 0; i < nThreads; ++i)
GN> {
GN> void* retVal = NULL;
GN> pthread_join(threads[i], &retVal);
GN> assert(retVal == NULL);
GN> }
GN> return 0;
GN>}
GN>// compile: g++ a.cpp -ggdb -lpthread -lmysqlclient_r && gdb ./a.out
GN>
Проблема в многопоточности и инициализации ресурсов по 100500 раз. Сделай инициализацию и закрытие базы за пределами тредов, после этого проверь свой код на race-condiction-ы. Запускать такой код лучше под нагрузкой которую можно сэмулировать с помощью dd.
ну проблема же не в том, что инициализация сильно часто происходит, а проблема что mysql библиотека это как-то неправильно обрабатывает? Насколько я понимаю, mysql ресурс всеравно нужно создавать один в каждом треде -- даже в документации по mysql написано что в нельзя использовать в треде А то, что инициализировано в треде Б. То есть каждому треду нужен свой ресурс.
К тому же, инициализация не полмается, ломается коннект()