mysql_init()线程安全问题

来源:互联网 发布:以色列粮食进口数据 编辑:程序博客网 时间:2024/06/11 15:45

写了个C++的多线程压力测试工具,写了个压测mysql的例子,调用mysql就使用myqsl的c api,


调用mysql的业务代码如下:(都是在线程内部)

        void init(){            //pthread_mutex_lock(&work_mutex);            my_connection=mysql_init(NULL);            if(mysql_real_connect(my_connection,"10.1.147.9","wangzytest","a1234561","wangzy",8066,NULL,0)){                printf("connection successfule \n");            }else{                fprintf(stderr,"connection failed\n");                if(mysql_errno(my_connection)){                    fprintf(stderr,"%d,%sn",mysql_errno(my_connection),mysql_error(my_connection));                    exit(0);                }                   }               //pthread_mutex_unlock(&work_mutex);        }           int mysql_execute(Result *rs){            if(mysql_query(my_connection,"select * from users")){                rs->result=false;                rs->msg = string(mysql_error(my_connection));                return 0;            }else{                //suppose in the perf test ,wo don't case the mysql query value only care if the query is successfule;                //so here i just free the query result                mysql_result = mysql_store_result(my_connection);                rs->result=true;                rs->msg="ok";                mysql_free_result(mysql_result);                return 1;            }               }           void del(){            mysql_close(my_connection);        }  


先调用一次init()

然后循环调用mysql_execute(),主线程来控制退出时间

最后执行完的时候,再调用一次del()函数


实际执行的时候,在虚拟机上执行1000个并发都没有问题,但是一旦将bin文件拷贝到物理机上执行,在10个线程以下,怎么执行都不会出错,但是线程数大于20个的时候,就会有很大的概率出现sigmentfault


仔细看了下代码实在是看不出哪里有问题,因为本地虚拟机1000个线程跑了20多次,一次都没出现问题. 没办法,只好用coredump来看下问题


查看堆栈

(gdb) where
#0  0x00007fce34f54bf9 in ?? () from /usr/lib64/libmysqlclient.so.16
#1  0x00007fce34f54f23 in ?? () from /usr/lib64/libmysqlclient.so.16
#2  0x00007fce34f5512f in get_charset_by_csname () from /usr/lib64/libmysqlclient.so.16
#3  0x00007fce34f7836a in mysql_init_character_set () from /usr/lib64/libmysqlclient.so.16
#4  0x00007fce34f79b9e in mysql_real_connect () from /usr/lib64/libmysqlclient.so.16
#5  0x0000000000405109 in MultiThread::init (this=0x7fce2800ed30) at run.cpp:130
#6  0x0000000000406af5 in MultiThread::run (this=0x7fce2800ed30) at run.cpp:55
#7  0x0000000000403cef in Thread::run1 (this=0x7fce2800ed30) at ../../include/Thread.h:61
#8  0x0000000000403d2d in Thread::run0 (pVoid=0x7fce2800ed30) at ../../include/Thread.h:45
#9  0x000000304ce064a7 in start_thread () from /lib64/libpthread.so.0
#10 0x000000304c6d3c2d in clone () from /lib64/libc.so.6


可以看到,是在mysql_real_connect() 的时候出错了,最后一个调用函数是get_charset_by_csname () ,也没有其他的信息,可以确定不是自己代码的问题

所以怀疑mysql 的cpi在连接阶段是存在线程不安全的


最后查出来是mysql_init(NULL); 是线程不安全的,在本地线程的相关数据的初始化的时候,会出现问题

简单的解决办法:

在mysql_real_connect()阶段加锁,因为这个是每个线程初始化的时候,只做一次的操作,因此也不会有什么性能损耗,添加了红色代码,再次测试就没有什么问题了






原创粉丝点击