libmysqlclient + threads + gdb = ?
От: green.nsk  
Дата: 13.08.12 21:28
Оценка:
Если вкратце, многоуважаемый Олл, есть примерно такой кусов кода (см. ниже). Все вроде бы работает (пишем под линукс), но с с некоторых пор (с каких пор, к сожалению, выяснить не удалось -- произошел какой-то апдейт дебиана или что-то изменилось в нашем коде), стал ломаться вызов 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
mysql libmysql threads pthread gdb
Re: libmysqlclient + threads + gdb = ?
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 14.08.12 11:40
Оценка:
Здравствуйте, 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.
Sic luceat lux!
Re[2]: libmysqlclient + threads + gdb = ?
От: green.nsk  
Дата: 17.08.12 19:58
Оценка:
ну проблема же не в том, что инициализация сильно часто происходит, а проблема что mysql библиотека это как-то неправильно обрабатывает? Насколько я понимаю, mysql ресурс всеравно нужно создавать один в каждом треде -- даже в документации по mysql написано что в нельзя использовать в треде А то, что инициализировано в треде Б. То есть каждому треду нужен свой ресурс.

К тому же, инициализация не полмается, ломается коннект()
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.