Como Fazer um Cliente em Threads
A biblioteca cliente é quase segura com threads. O maior problema é que a subrotinas em net.c
que leem dos sockets não são seguras a interrupções. Isto foi feito pesando que você pudesse desejar ter o seu próprio alarme que possa quebrar uma longa leitura no servidor. Se você instalar manipuladores de interrupção para a interrupção SIGPIPE
, o manipulador socket deve ser segura com threads.
Nos binários antigos que distribuímos em nosso web site (http://www.mysql.com/), as bibliotecas clientes não estão normalmente compiladas com a opção de segurança com thread (os binários são complados com segurança com thread por padrão). Distribuições binárias mais novas devem ter uma biblioteca normal e uma segura com threads.
Para termos um cliente em threads onde você pode interromper o cliente a partir de outras threads a definir tempo limites ao falar com o servidor MySQL, você deve utilizar as bibliotecas -lmysys
, -lmystrings
, e -ldbug
e o código net_serv.o
que o servidor utiliza.
Se você não precisar de insterrupções ou de tempos limites, você pode apenas compilar um biblioteca cliente (mysqlclient_r)
segura com threads e utilizá-las. Leia "API C do MariaDB". Neste caso você não precisa se preocupar com o arquivo objeto net_serv.o
ou outras bibliotecas MySQL.
Quando usar um cliente em thread e você quiser utilizar tempos limite e interrupções, você pode ter um grande uso das rotinas no arquivo thr_alarm.c
. Se você estiver utilizando rotinas da biblioteca mysys
, a única coisa que você deve lembrar é de chamar primeiro my_init()
! Leia "Descrição das Funções de Threads da API C".
Todas as funções com excessão de mysql_real_connect()
são seguras com thread por padrão. As anotações seguintes descrevem como compilar uma biblioteca cliente segura com thread e utilizá-la de maneira segura. (As anotações abaixo para mysql_real_connect()
na verdade se aplicam também a mysql_connect()
, mas como mysql_connect()
está obsoleto, você deve utilizar mysql_real_connect()
.)
Para tornar mysql_real_connect()
seguro com thread, você deve recompilar a biblioteca cliente com este comando:
shell> ./configure --enable-thread-safe-client
Isto irá criar uma biblioteca cliente libmysqlclient_r
. (Assumindo que o seu SO tenha a função gethostbyname_r()
segura com thread). Esta biblioteca é segura com thread por conexão. Você pode deixar duas threads compartilharem a mesma conexão com os seguintes cuidados:
- Duas threads não podem enviar uma consaulta ao servidor MariaDB ao mesmo tempo na mesma conexão. Em particular, você deve assegurar que entre um
mysql_query()
emysql_store_result()
nenhuma outra thread está usando a mesma conexão. - Várias threads podem acessár resultados diferentes que são recuperados com
mysql_store_result()
. - Se você utilizar
mysql_use_result
, você terá que assegurar que nenhuma outra thread está usando a mesma conexão até que o resultado seja fechado. No entanto, é melhor para clientes em threads que compartilham a mesma conexão utilizarmysql_store_result()
. - Se você quiser utilizar múltiplas threads na mesma conexão, você deve ter uma trava mutex na combinação das chamadas
mysql_query()
emysql_store_result()
. Uma vez quemysql_store_result()
esteja pronto, a trva pode ser liberada e outras threads podem utilizar a mesma conexão. - Se você programa com threads POSIX, você pode utilizar
pthread_mutex_lock()
epthread_mutex_unlock()
para estabelecer e liberar uma trava mutex.
Você precisa saber o seguinte se você tiver uma thread que estiver chamando funções MariaDB que não criaram a conexão ao Banco de Dados MariaDB:
Quando você chamar mysql_init()
ou mysql_connect()
, MariaDB irá criar um variável especica da thread para a thread que é utilizada pela bibklioteca de depuração (entre outra coisas).
Se você chamar uma função MySQL, antes da thread chamar mysql_init()
ou mysql_connect()
, a thread não terá as variáveis específicas de thread necessárias alocadas e você acabará finalizando com uma descarga de memória mais cedo ou mais tarde.
Para fazer que as coisas funcionem suavemente você tem que fazer o seguinte:
- Chama
my_init()
no início do seu programa se for chamar qualquer outra função MariaDB antes de chamarmysql_real_connect()
. - Chame
mysql_thread_init()
no manipulador de thread antes de chamar qualquer outra função MariaDB. - Na thread, chame
mysql_thread_end()
antes de chamarpthread_exit()
. Isto irá liberar a memória usada pelas variáveis específicas da thread do MariaDB.
Você pode obter alguns erros devido a símbolos indefinidos ao ligar seu cliente com libmysqlclient_r
. Na maioria dos casos isto ocorre por não estar incluída a biblioteca de threads na linha de ligação/compilação.