本节提供了编写使用 MySQL C API 中线程相关函数的客户端程序的指南。有关这些函数的更多信息,请参阅 第 8.2 节“C API 线程函数说明”。有关使用它们的源代码示例,请查看 MySQL 源代码发行版中的 client
目录。
mysqlimport 的源代码在与
--use-threads
选项关联的代码中使用了线程。mysqlslap 的源代码使用线程来设置并发工作负载,以测试服务器在高负载下的运行情况。
作为线程编程的替代方法,应用程序可能会发现异步(非阻塞)C API 函数很有用。这些函数使应用程序能够向服务器提交多个未完成的请求,并使用轮询确定每个请求何时完成。有关更多信息,请参阅 第 7 章“C API 异步接口”。
如果在将线程程序链接到 MySQL 客户端库时出现未定义引用错误,则最可能的原因是您没有在链接/编译命令中包含线程库。
客户端库几乎是线程安全的。最大的问题是从套接字读取数据的 sql/net_serv.cc
中的子例程不是中断安全的。这样做是考虑到您可能希望拥有自己的警报,可以在长时间读取服务器时中断读取。如果您为 SIGPIPE
中断安装了中断处理程序,则套接字处理应该是线程安全的。
为了避免在连接终止时中止程序,MySQL 在第一次调用 mysql_library_init()
、mysql_init()
或 mysql_connect()
时会阻塞 SIGPIPE
。要使用您自己的 SIGPIPE
处理程序,请先调用 mysql_library_init()
,然后安装您的处理程序。
客户端库在每个连接上都是线程安全的。两个线程可以共享同一个连接,但需要注意以下几点:
-
除非您使用前面提到的异步 C API 函数,否则多个线程不能在同一个连接上同时向 MySQL 服务器发送查询。特别是,您必须确保在一个线程中调用
mysql_real_query()
(或mysql_query()
)和mysql_store_result()
之间,没有其他线程使用同一个连接。为此,请在您的mysql_real_query()
(或mysql_query()
)和mysql_store_result()
调用对周围使用互斥锁。在mysql_store_result()
返回后,可以释放锁,其他线程可以查询同一个连接。如果您使用 POSIX 线程,则可以使用
pthread_mutex_lock()
和pthread_mutex_unlock()
来建立和释放互斥锁。注意如果您查看 MySQL 源代码发行版中的程序,您会看到调用
native_mutex_lock()
和native_mutex_unlock()
,而不是调用pthread_mutex_lock()
和pthread_mutex_unlock()
。后两个函数在thr_mutex.h
头文件中定义,并映射到特定于平台的互斥锁函数。 多个线程可以访问使用
mysql_store_result()
检索的不同结果集。要使用
mysql_use_result()
,您必须确保在结果集关闭之前没有其他线程使用同一个连接。但是,对于共享同一个连接的线程客户端来说,最好使用mysql_store_result()
。
如果一个线程没有创建到 MySQL 数据库的连接,而是调用 MySQL 函数,请考虑以下因素:
当您调用 mysql_init()
时,MySQL 会为调试库(以及其他用途)使用的线程创建一个线程特定的变量。如果您在线程调用 mysql_init()
之前调用 MySQL 函数,则该线程没有必要的线程特定的变量,您很可能会迟早遇到核心转储。为了避免问题,您必须执行以下操作:
在任何其他 MySQL 函数之前调用
mysql_library_init()
。它不是线程安全的,因此请在创建线程之前调用它,或者使用互斥锁保护调用。安排在调用任何 MySQL 函数之前,在线程处理程序的早期调用
mysql_thread_init()
。(如果您调用mysql_init()
,它会为您调用mysql_thread_init()
。)在线程中,在调用
pthread_exit()
之前调用mysql_thread_end()
。这将释放 MySQL 线程特定的变量使用的内存。
前面关于 mysql_init()
的说明也适用于 mysql_connect()
,后者会调用 mysql_init()
。