3.4 Написание программ с многопоточными клиентами API C
В этом разделе приводятся рекомендации по написанию клиентских программ, использующих функции, связанные с потоками в MySQL C API. Дополнительную информацию об этих функциях см. в разделе 7.2 «Описание функций API C с поддержкой потоков». Примеры исходного кода, использующего эти функции, см. в каталоге client дистрибутива исходного кода MySQL:
Исходный код mysqlimport использует многопоточность в коде, связанном с соответствующим параметром.
Исходный код mysqlslap использует потоки для создания одновременных нагрузок, чтобы проверить работу сервера при высокой нагрузке.
Если при компоновке многопоточной программы с библиотекой MySQL-клиентов возникают ошибки undefined-reference, наиболее вероятная причина заключается в том, что вы не включили библиотеки потоков в команду компоновки/компиляции.
Библиотека клиента практически потокобезопасна. Самая большая проблема заключается в том, что подпрограммы в sql/net_serv.cc, которые считывают данные из сокетов, не безопасны для прерываний. Это было сделано с учетом того, что вы можете захотеть иметь свой собственный механизм прерывания, который может прервать длительное чтение данных от сервера. Если вы установите обработчики прерываний для прерываний SIGPIPE, обработка сокетов должна стать потокобезопасной.
Чтобы избежать аварийного завершения программы при разрыве соединения, MySQL блокирует SIGPIPE при первом вызове mysql_library_init(), mysql_init() или mysql_connect(). Чтобы использовать свой собственный обработчик SIGPIPE, сначала вызовите mysql_library_init(), а затем установите свой обработчик.
Библиотека клиента потокобезопасна на уровне соединения. Два потока могут использовать одно и то же соединение с учетом следующих оговорок:
-
Несколько потоков не могут одновременно отправлять запрос на 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, вместо вызовов
pthread_mutex_lock()иpthread_mutex_unlock()вы увидите вызовыnative_mutex_lock()иnative_mutex_unlock(). Последние функции определены в заголовочном файлеthr_mutex.hи соответствуют платформным функциям взаимного исключения. Несколько потоков могут обращаться к различным наборам результатов, которые извлекаются с помощью
mysql_store_result().Для использования
mysql_use_result()необходимо убедиться, что ни один другой поток не использует то же соединение, пока набор результатов не будет закрыт. Однако для многопоточных клиентов, которые используют одно и то же соединение, лучше использоватьmysql_store_result().
Если поток не создаёт соединение с базой данных MySQL, но вызывает функции MySQL, учтите следующее:
При вызове mysql_init(), MySQL создаёт специфичную для потока переменную для потока, которая используется библиотекой отладки (среди прочего). Если вы вызываете функцию MySQL перед тем, как поток вызвал mysql_init(), у потока нет необходимых специфичных для потока переменных, и в конечном итоге он может привести к сбою.
Чтобы избежать проблем, выполните следующие действия:
Вызовите
mysql_library_init()перед любыми другими функциями MySQL. Она не потокобезопасна, поэтому вызовите её до создания потоков или защитите вызов с помощью взаимного исключения.Организуйте вызов
mysql_thread_init()на раннем этапе обработчика потока перед вызовом любой функции MySQL. (Если вы вызываетеmysql_init(), она вызываетmysql_thread_init()за вас.)В потоке вызовите
mysql_thread_end()перед вызовомpthread_exit(). Это освобождает память, используемую специфичными для потока переменными MySQL.
Предыдущие замечания относительно mysql_init() также применяются к mysql_connect(), которая вызывает mysql_init().
© 2025 Oracle
Licensed under the GPLv2 License.