第25章:API和库 / 25.2. MySQL C API / 25.2.15. 如何生成线程式客户端

客户端库总是线程安全的。最大的问题在于从套接字读取的net.c中的子程序并不是中断安全的。或许你可能希望用自己的告警中断对服务器的长时间读取,以此来解决问题。如果为SIGPIPE中断安装了中断处理程序,套接字处理功能应是线程安全的。

为了避免连接中断时放弃程序,MySQL将在首次调用mysql_server_init()mysql_init()mysql_connect()时屏蔽SIGPIPE。如果你打算使用自己的SIGPIPE处理程序,首先应调用mysql_server_init(),然后安装你的处理程序,

在较旧的发布在我方网站上(http://www.mysql.com/)的二进制版本中,未用线程安全的选项对客户端库进行正常编译(默认情况下,编译的Windows二进制版本是线程安全的)。较新的二进制分发版应是正常的和线程安全的客户端库。

为了获得能从其他线程中断客户端的线程式客户端,并在与MySQL服务器通信时设置超时,应使用“-lmysys”、“-lmystrings”-ldbug”库,以及服务器使用的net_serv.o代码。

如果你不需要使用中断或超时,可编译线程安全客户端库(mysqlclient_r)并使用它。。请参见25.2节,“MySQL C API”。在该情况下,不必担心net_serv.o对象文件或其他MySQL库。

使用线程式客户端并打算使用超时或中断时,可更好地利用thr_alarm.c文件中的子程序。如果你正在使用来自mysys库的子程序,唯一需要记住的事是首先调用my_init()!请参见25.2.11节,“C API线程函数介绍”

对于除mysql_real_connect()外的所有函数,在默认情况下它们均是线程安全的。在下面的说明中,介绍了编译线程安全客户端库的方法,以及以线程安全方式使用它的方法。(下面关于mysql_real_connect()的说明实际上也适用于mysql_connect(),但由于mysql_connect()已不再被重视,总应尽量使用mysql_real_connect())。

要想使mysql_real_connect()成为线程安全的,必须用下述命令再次编译客户端库:

shell> ./configure --enable-thread-safe-client

它创建了线程安全客户端库libmysqlclient_r。(假定你的操作系统有线程安全的gethostbyname_r()函数)。按照连接,该库是线程安全的。可遵循下述警告,使两个线程共享相同的连接:

·         在相同的连接上,两个线程不能同时将查询发送到MySQL服务器。尤其是,必须确保在mysql_query()mysql_store_result()之间,没有使用相同连接的其他线程。

·         很多线程均能访问由mysql_store_result()检索的不同结果集。

·         如果使用了mysql_use_result,务必确保无其他线程正在使用相同的连接,直至关闭了结果集为止。然而,对于线程式客户端,最好是共享相同的连接以使用mysql_store_result()

·         如果打算在相同的连接上使用多个线程,必须在mysql_query()mysql_store_result()调用组合上拥有互斥锁。一旦mysql_store_result()准备就绪,可释放锁定,其他线程可在相同的连接上执行查询。

·         如果使用POSIX线程进行编程,可使用pthread_mutex_lock()pthread_mutex_unlock()来建立并释放互斥锁。

如果你有1个调用MySQL函数的线程,而该函数未创建与MySQL数据库的连接,就需了解下述事宜:

调用mysql_init()mysql_connect()时,MySQL会为调试库使用的线程创建与线程相关的变量(尤其)。

在线程调用mysql_init()mysql_connect()之前,如果调用了MySQL函数,该线程将没有所需的线程类变量,而且你很可能或早或晚结束于内核转储。

要想使这些操作平稳工作,需要采取下述措施:

1.    如果程序在调用mysql_real_connect()之前需要调用任何其他MySQL函数,请在启动程序时调用my_init()

2.    调用任何MySQL函数之前,在线程处理程序中调用mysql_thread_init()

3.    在线程中,调用pthread_exit()之前请调用mysql_thread_end()。这样,就能释放MySQL线程类变量使用的内存。

将客户端链接到libmysqlclient_r时,如果存在未定义的符号,可能会出错。在大多数情况下,其原因在于,未将线程库包含在link/compile行上。