这个问题在之前的一篇文章中提到过,通过更换libmysqlclient的版本暂时规避了这个问题,但是后面使用过程中发现,其实还是不对的,启动时mysql_init有几率会返回一个空指针,后面的逻辑就走不下去了.所以怀疑这个问题其实和库的版本无关, 换了个库版本只是让问题的表现形式不同了而已.
上mysql官网继续查阅文档,发现一篇文档如下:
https://dev.mysql.com/doc/refman/5.7/en/mysql-init.html
In a nonmulti-threaded environment, mysql_init() invokes mysql_library_init() automatically as necessary. However, mysql_library_init() is not thread-safe in a multi-threaded environment, and thus neither is mysql_init(). Before calling mysql_init(), either call mysql_library_init() prior to spawning any threads, or use a mutex to protect the mysql_library_init() call. This should be done prior to any other client library call.
大概意思是 mysql_init 会检查 mysql_library_init这个函数是否有调用过,如果没调用过就会去调用一次, 而mysql_library_init这个函数不是线程安全的,所以导致mysql_init 也不是线程安全的, 所以需要在调用libmysqlclient 库里面的任何一个函数之前调用mysql_library_init, 用面向对象的思想来理解,就类似于单例模式的主动初始化.
为了验证问题是否被解决,我写了如下测试代码:
上面的代码开启了100个线程,每个线程内只做一件事,就是创建一个mysql连接并连接到mysql服务器.
毫无悬念的,直接执行会导致crash.
现在,把他修改一下:
|
|
在创建连接之前调用 mysql_library_init 函数,编译运行后发现可以成功创建连接,程序不会crash.
至此这个问题算是最终解决了.