32.20. 多线程程序中的行为 #
从版本 17 起,libpq 始终是可重入且线程安全的。不过仍有一条限制:不得有两个线程同时操作同一个 PGconn 对象。特别是,不能从不同线程通过同一个连接对象并发发出命令。(如果需要并发运行命令,请使用多个连接。)
PGresult 对象在创建后通常是只读的,因此可以在线程之间自由传递。不过,如果你使用第 32.11 节或第 32.13 节中描述的任何会修改 PGresult 的函数,则需要自行避免对同一个 PGresult 执行并发操作。
在较早版本中,libpq 能否提供线程支持取决于编译选项。下面这个函数允许查询 libpq 的线程安全状态:
PQisthreadsafe#返回 libpq 库的线程安全状态。
int PQisthreadsafe();
如果 libpq 是线程安全的则返回 1,否则返回 0。在版本 17 及以上始终返回 1。
已弃用的函数 PQrequestCancel 和 PQoidStatus 不是线程安全的,不应在多线程程序中使用。PQrequestCancel 可以用 PQcancelBlocking 替代;PQoidStatus 可以用 PQoidValue 替代。
如果你在应用程序中使用 Kerberos(除了 libpq 内部之外),则需要在 Kerberos 调用周围加锁,因为 Kerberos 函数不是线程安全的。可参考 libpq 源代码中的 PQregisterThreadLock 函数,它提供了一种在 libpq 与应用程序之间协作加锁的方法。(注意,只有在不存在打开的连接时,调用 PQregisterThreadLock 才是安全的。)客户端可以使用 PQgetThreadLock 获取当前的锁回调;如果未注册自定义回调,则使用默认回调。
同样地,如果你在应用程序中使用 Curl,并且在启动新线程之前还没有先对 libcurl 进行全局初始化,那么你也需要通过 PQregisterThreadLock 协作地为任何可能初始化 libcurl 的代码加锁。对于支持线程安全初始化的较新版本 Curl,这一限制已被解除;这类构建可以通过其版本元数据中声明的 threadsafe 特性识别出来。