ошибка многопоточного доступа MySQL - PullRequest
0 голосов
/ 16 декабря 2009

Я написал простую многопоточную программу на C для доступа к MySQL, она прекрасно работает, кроме , когда я добавляю функции usleep () или sleep () в каждую функцию потока. я создал два метода в основном методе

int main(){
        mysql_library_init(0,NULL,NULL);
        printf("Hello world!\n");
        init_pool(&p,100);
        pthread_t producer;
        pthread_t consumer_1;
        pthread_t consumer_2;
        pthread_create(&producer,NULL,produce_fun,NULL);
        pthread_create(&consumer_1,NULL,consume_fun,NULL);
        pthread_create(&consumer_2,NULL,consume_fun,NULL);
        mysql_library_end();
}



   void * produce_fun(void *arg){
    pthread_detach(pthread_self());
    //procedure
    while(1){
        usleep(500000);
        printf("producer...\n");
        produce(&p,cnt++);
    }
    pthread_exit(NULL);
}

void * consume_fun(void *arg){
    pthread_detach(pthread_self());
    MYSQL db;
    MYSQL *ptr_db=mysql_init(&db);
    mysql_real_connect();

    //procedure
    while(1){
        usleep(1000000);
        printf("consumer...");
        int item=consume(&p);
        addRecord_d(ptr_db,"test",item);
    }
    mysql_thread_end();
    pthread_exit(NULL);
}

void addRecord_d(MYSQL *ptr_db,const char *t_name,int item){
    char query_buffer[100];
    sprintf(query_buffer,"insert into %s values(0,%d)",t_name,item);
//pthread_mutex_lock(&db_t_lock);
    int ret=mysql_query(ptr_db,query_buffer);
    if(ret){
        fprintf(stderr,"%s%s\n","cannot add record to ",t_name);
        return;
    }

    unsigned long long update_id=mysql_insert_id(ptr_db);
//    pthread_mutex_unlock(&db_t_lock);
    printf("add record (%llu,%d) ok.",update_id,item);
}

ошибки вывода программы, такие как:

[Thread debugging using libthread_db enabled]
[New Thread 0xb7ae3b70 (LWP 7712)]
Hello world!
[New Thread 0xb72d6b70 (LWP 7713)]
[New Thread 0xb6ad5b70 (LWP 7714)]
[New Thread 0xb62d4b70 (LWP 7715)]
[Thread 0xb7ae3b70 (LWP 7712) exited]
producer...
producer...
consumer...consumer...add record (31441,0) ok.add record (31442,1) ok.producer...
producer...
consumer...consumer...add record (31443,2) ok.add record (31444,3) ok.producer...
producer...
consumer...consumer...add record (31445,4) ok.add record (31446,5) ok.producer...
producer...
consumer...consumer...add record (31447,6) ok.add record (31448,7) ok.producer...
Error in my_thread_global_end(): 2 threads didn't exit
[Thread 0xb72d6b70 (LWP 7713) exited]
[Thread 0xb6ad5b70 (LWP 7714) exited]
[Thread 0xb62d4b70 (LWP 7715) exited]

Program exited normally.

и когда я добавляю pthread_mutex_lock в функцию addRecord_d, ошибка все еще существует. Так в чем же проблема?

Ответы [ 2 ]

1 голос
/ 15 марта 2010

Проблема в том, что вы вызываете mysql_library_end () слишком рано (особенно с помощью usleep () в потоках). Можно завершить основной поток и продолжить работу других потоков, но это не рекомендуется. Ваше решение добавить pthread_join () - лучшее. Вы также можете устранить mysql_library_end (), и это будет работать.

0 голосов
/ 16 декабря 2009

Пока потоки вашего производителя и потребителя спят, они держатся за соединения mysql, которые открыты на время действия соответствующих функций.

Когда программа пытается завершиться, скорее всего, эти потоки спят и не могут получить сигнал завершения. Отсюда ошибка от my_thread_global_end().

У меня сейчас нет доступа к среде разработки, поэтому я не могу попробовать ваш пример. Но я думаю, что это может обойти ошибку, хотя это был бы крайне неэффективный код (пример из функции потребление_фона):

//procedure
while(1){
    usleep(1000000);

    MYSQL *ptr_db=mysql_init(&db);
    mysql_real_connect();

    printf("consumer...");
    int item=consume(&p);
    addRecord_d(ptr_db,"test",item);

    mysql_thread_end();
}

В двух словах, приведенный выше пример должен привести к установлению и закрытию соединения вне цикла ожидания. Я не думаю, что это лучший код, но в целях вашей иллюстрации это должно избавить от ошибок.

Имейте в виду: это заставит вас открывать и закрывать соединения в цикле, что будет крайне неэффективным использованием ресурсов в среде производственного типа, поэтому не делайте этого в реальной жизни. :)

Надеюсь, это поможет.

...