根据官方文档,MySQL 提供的C API中,除了mysql_real_init()外,默认都是线程安全的,但是实际情况是,mysql_query()参数的不加限制的使用,将导致出现问题。

异常情景如下:

query1和query2使用同一个Connection进行query查询,设thread_1调用query1,thread_2调用query2,当两个线程不加限制的时候,会出现串数据的情况。

即:query1读取到了query2的结果。

更严重,有可能导致mysql_query()抛出异常

解决办法,自阿query1(),query2()的入口和出口加上信号量semaphore,代码结构如下:

1、声明semaphore并初始化

sem_init(&sem,0,1);

第一个参数是信号量的指针,第二个参数可以设置为0表示不参与进程同步,第三个参数表示资源可用的数量(实际上semaphore可以理解为一个int量),这里第一次必须要能够查询只不过共享了唯一一个Connection,所以设置为1

2、对于query1()和query()2的改造。
如下:

void query1()
{
//等待信号量,当为1的时候,减为0,并继续执行;否则阻塞
sem_wait(&sem);

//执行mysql_query(...)

//释放信号量,信号量加1
sem_post()
}

query2的改造同query1()

经过了上面的改造,query1和query2就是线程安全的了,任何线程都可以不加限制的调用这两个函数了!

3、性能下降

使用信号量同步一定会导致性能下降,下面是一些测试参数。

前提:query1和query2各查询10000次

没有使用信号量之前:

450000

使用了信号量之后

490000

还是可以接受的,毕竟换来了安全。