您的位置:首页 > 数据库 > MySQL

mysql_init()线程安全问题

2012-11-12 10:28 190 查看
写了个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()阶段加锁,因为这个是每个线程初始化的时候,只做一次的操作,因此也不会有什么性能损耗,添加了红色代码,再次测试就没有什么问题了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: