A sobrecarga 1 de ParseInput (todos os parâmetros
explícitos) é totalmente segura entre threads. Cada chamada opera
inteiramente na sua própria pilha e nas suas próprias variáveis locais;
não é lido nem gravado qualquer estado partilhado. Pode ser chamada em
simultâneo a partir de qualquer número de threads sem necessidade de
sincronização.
// É seguro chamar a partir de múltiplas threads simultaneamente.
R := ParseInput(Input, itDate, '~', [], sopEqual, sqlMySQL);As sobrecargas 2–5 lêem a variável global
GDefaultDialect no momento da chamada. São seguras para
utilização a partir de múltiplas threads, desde que
SetSQLDialect nunca seja chamada após o início do
processamento multithread. O padrão típico de segurança consiste em
chamar SetSQLDialect uma vez durante o arranque da
aplicação — antes da criação de quaisquer threads secundárias — e, em
seguida, utilizar as sobrecargas 2–5 livremente a partir de qualquer
thread:
// Thread principal, arranque da aplicação.
SetSQLDialect(sqlElevateDB);
// Threads de trabalho: seguras, porque `SetSQLDialect` nunca mais é chamado.
R := ParseInput(Input, itDate);Se o dialecto tiver de ser alterado em tempo de execução enquanto as threads estão a funcionar, utilize exclusivamente a sobrecarga 1 e passe o dialecto explicitamente em cada chamada.
Chamadas simultâneas a Parse() em instâncias
diferentes de TEgStrParser são seguras
para threads. Cada instância armazena o seu próprio
FSqlDialect e passa-o diretamente para a sobrecarga 1 de
ParseInput. Nenhuma variável global é lida ou gravada.
// Seguro: Parser1 e Parser2 são instâncias distintas.
// Thread A:
R := Parser1.Parse(Input1, itDate);
// Thread B (simultaneamente):
R := Parser2.Parse(Input2, itInteger);As chamadas simultâneas à mesma instância de
TEgStrParser não são seguras para threads.
FLastResult e FLastControl são gravados em
cada chamada sem sincronização; as gravações simultâneas produzem uma
corrida de dados.
Se um único componente tiver de ser partilhado entre threads, proteja cada chamada com um bloqueio:
// Um bloqueio por instância de componente partilhada.
FCritSect.Enter;
try
R := Parser1.Parse(Input, itDate);
finally
FCritSect.Leave;
end;Em alternativa, crie uma instância separada de
TEgStrParser por thread, ou utilize diretamente a
sobrecarga 1 de ParseInput nas threads de trabalho e
reserve o componente para a thread principal.
SetSQLDialect e GetSQLDialect acedem à
variável global GDefaultDialect sem sincronização. Não
chame nenhuma destas funções a partir de uma thread enquanto outra
thread possa estar a chamar as sobrecargas 2–5 de
ParseInput ou o outro acessador de dialeto.
// Inseguro: o dialeto pode alterar-se enquanto a thread de trabalho o lê.
// Thread de trabalho:
R := ParseInput(Input, itDate); // lê GDefaultDialect
// Thread principal (simultaneamente):
SetSQLDialect(sqlMySQL); // escreve em GDefaultDialectParseInput lê FormatSettings (as definições
globais de localização do Delphi) para inicializar os registos
SqlFmt e LocaleFmt por cada chamada. No Delphi
11 e versões posteriores, FormatSettings é, por
predefinição, uma variável local da thread quando
{$DEFINE POSIX} está definido ou quando o RTL está
configurado para segurança de threads. No Windows, com as definições
predefinidas do RTL, FormatSettings é uma variável global;
alterá-la a partir de uma thread enquanto outra está a chamar
ParseInput constitui uma corrida de dados.
Na prática, FormatSettings é normalmente definida uma
vez no arranque e não é alterada posteriormente, o que é seguro. Se
forem necessárias substituições de localização por thread, utilize
diretamente as sobrecargas das funções RTL baseadas em
TFormatSettings, em vez de modificar a variável global.
| Cenário | Seguro? |
|---|---|
Sobrecarga 1 de ParseInput, múltiplas threads |
Sim |
Sobrecargas 2–5 de ParseInput, múltiplas threads,
SetSQLDialect chamado apenas no arranque |
Sim |
Sobrecargas 2–5 de ParseInput,
SetSQLDialect chamado em tempo de execução a partir de
outra thread |
Não |
TEgStrParser.Parse(), instâncias diferentes, múltiplas
threads |
Sim |
TEgStrParser.Parse(), mesma instância, múltiplas
threads |
Não |
SetSQLDialect / GetSQLDialect em
simultâneo com as sobrecargas 2–5 |
Não |