Threading & Multi-Threading
Padrões de threading em FreePascal/Lazarus — TThread, Synchronize, Queue, TCriticalSection, TEvent, thread-safety, Producer-Consumer e cancelamento
Install / Use
npx skills add delphicleancode/lazarus-spec-kit --skill threadingInstalls into whichever agent you are using.
Gemini Rules
Gemini CLI config
Quality Score
Category
Development & EngineeringSupported Platforms
Tags
Our assessment of Threading & Multi-Threading
Threading & Multi-Threading scores 76/100 on our quality scale, 3660th of 4,573 Development & Engineering skills we index.
Its Gemini Rules is 13 KB long, well organised into 21 sections with 12 code examples: a thorough specification that gives an agent plenty to work with.
It has no GitHub stars yet, so there is no community track record; judge it on its content.
Maintenance, license and trust
- The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 74/100, with 3 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.
AI review by kimi-k2.7-code on 2026-10-02. Automated pattern scan on 2026-10-01. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
Threading & Multi-Threading compared with similar skills
All 4 of these similar skills score higher than Threading & Multi-Threading; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| Threading & Multi-Threading (this skill)by delphicleancode | 76 | 0 | 6mo ago | Gemini Rules |
| ai-job-searchby MadsLorentzen | 100 | 45.3k | today | CLAUDE.md |
| claude-howtoby luongnv89 | 100 | 41.8k | 8d ago | CLAUDE.md |
| algorithmic-artby anthropics | 100 | 177.9k | 16d ago | SKILL.md |
| interview-meby addyosmani | 100 | 102.0k | 5d ago | SKILL.md |
Frequently asked questions
- How do I install Threading & Multi-Threading?
- Run
npx skills add delphicleancode/lazarus-spec-kit. The install tabs above show the steps for each supported agent. - Which AI agents does Threading & Multi-Threading work with?
- It is written for Gemini CLI, as a Gemini Rules file. Other agents that read the same format can often use it too.
- Is Threading & Multi-Threading safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It declares no license and scores 74/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is Threading & Multi-Threading still maintained?
- The repository was last updated about 6 months ago. That is recent enough to be usable, but agent tooling moves fast, so check the instructions against your agent's current version.
Skill content
View source on GitHubname: "Threading & Multi-Threading" description: "Padrões de threading em FreePascal/Lazarus — TThread, Synchronize, Queue, TCriticalSection, TEvent, thread-safety, Producer-Consumer e cancelamento"
Threading & Multi-Threading — Skill
Use esta skill ao trabalhar com threads e tarefas assíncronas em projetos FreePascal/Lazarus.
Quando Usar
- Ao executar operações demoradas sem bloquear a UI (LCL)
- Ao criar servidores/workers que processam requisições concorrentes
- Ao sincronizar acesso a recursos compartilhados
- Ao implementar cancelamento gracioso de threads
Regra de Ouro do Threading no Lazarus
NUNCA acesse componentes visuais (LCL) diretamente de uma thread secundária. Use
TThread.SynchronizeouTThread.Queuepara atualizar a UI.
Incompatibilidades FPC vs Delphi
IMPORTANTE: As seguintes primitivas do Delphi NÃO existem no FreePascal:
TTask,TTask.Run(PPL)TParallel.For(PPL)IFuture<T>,TFuture<T>(PPL)TInterlocked(classe estática)TMonitor(lock nativo de objeto)TThreadedQueue<T>(fila genérica thread-safe)TThread.CreateAnonymousThread(anonymous methods em threads)TThread.Current.CheckTerminatedTThread.NameThreadForDebuggingUse exclusivamente
TThread,TCriticalSection,TEvent,TThreadList,TMultiReadExclusiveWriteSynchronizere funções atômicas nativas (InterlockedIncrement,InterlockedDecrement,InterlockedExchange).
Abordagens Disponíveis no FPC
| Abordagem | Quando Usar | Complexidade |
|-----------|-------------|--------------|
| TThread (herança) | Controle total, workers permanentes | Média |
| TThread.Synchronize | Atualizar UI (bloqueante) | Baixa |
| TThread.Queue | Atualizar UI (não-bloqueante, PREFERIR) | Baixa |
| TCriticalSection | Seção de exclusão mútua (Enter/Leave) | Baixa |
| TThreadList | Lista thread-safe com LockList/UnlockList | Baixa |
| TEvent | Sinalização entre threads (WaitFor/SetEvent) | Média |
| TMultiReadExclusiveWriteSynchronizer | Cache: muitas leituras, poucas escritas | Média |
TThread — Padrão Principal no FPC
Thread com Herança (Recomendado para Workers)
uses
Classes, SysUtils;
type
/// <summary>
/// Worker thread para processamento em background.
/// Demonstra herança de TThread com cancelamento via Terminated.
/// </summary>
TDataProcessorThread = class(TThread)
private
FProgressCurrent: Integer;
FProgressTotal: Integer;
FErrorMsg: string;
procedure DoUpdateProgress;
procedure DoShowError;
protected
procedure Execute; override;
public
constructor Create;
end;
constructor TDataProcessorThread.Create;
begin
inherited Create(True); // Criar suspensa
FreeOnTerminate := True; // Auto-libera ao terminar
end;
procedure TDataProcessorThread.Execute;
var
I: Integer;
begin
FProgressTotal := 100;
try
for I := 0 to FProgressTotal - 1 do
begin
{ Verificar cancelamento em cada iteração }
if Terminated then
Exit;
{ Processar item }
ProcessItem(I);
FProgressCurrent := I + 1;
{ Atualizar UI via Queue (não-bloqueante) }
Queue(@DoUpdateProgress);
end;
except
on E: Exception do
begin
FErrorMsg := E.Message;
Queue(@DoShowError);
end;
end;
end;
procedure TDataProcessorThread.DoUpdateProgress;
begin
// Acessa LCL de forma segura aqui (roda na main thread)
frmMain.pbrProgress.Max := FProgressTotal;
frmMain.pbrProgress.Position := FProgressCurrent;
end;
procedure TDataProcessorThread.DoShowError;
begin
ShowMessage('Erro: ' + FErrorMsg);
end;
Uso da Thread Dedicada
procedure TfrmMain.btnProcessClick(Sender: TObject);
var
LThread: TDataProcessorThread;
begin
LThread := TDataProcessorThread.Create;
LThread.Start;
end;
procedure TfrmMain.btnCancelClick(Sender: TObject);
begin
{ Solicitar cancelamento gracioso }
if Assigned(FCurrentThread) then
FCurrentThread.Terminate;
end;
Synchronize vs Queue
| Método | Comportamento | Quando Usar |
|--------|--------------|-------------|
| TThread.Synchronize | Bloqueante — espera a main thread processar | Quando precisa do resultado da UI |
| TThread.Queue | Não-bloqueante — enfileira e continua | Progresso, logs, atualizações visuais |
{ Synchronize: BLOQUEIA a thread até a main thread processar }
Synchronize(@DoUpdateUI);
// A thread só continua AQUI depois que a main thread executou
{ Queue: NÃO BLOQUEIA — enfileira e continua imediatamente }
Queue(@DoUpdateUI);
// A thread continua IMEDIATAMENTE sem esperar
Recomendação: Prefira
Queuesempre que possível. UseSynchronizeapenas quando precisar de um resultado da UI de volta na thread.
Thread-Safety — Proteção de Recursos
TCriticalSection (unit syncobjs)
uses
syncobjs;
type
TThreadSafeCounter = class
private
FCount: Integer;
FLock: TCriticalSection;
public
constructor Create;
destructor Destroy; override;
procedure Increment;
function GetValue: Integer;
end;
constructor TThreadSafeCounter.Create;
begin
inherited;
FLock := TCriticalSection.Create;
FCount := 0;
end;
destructor TThreadSafeCounter.Destroy;
begin
FLock.Free;
inherited;
end;
procedure TThreadSafeCounter.Increment;
begin
FLock.Enter;
try
Inc(FCount);
finally
FLock.Leave; // SEMPRE no finally!
end;
end;
function TThreadSafeCounter.GetValue: Integer;
begin
FLock.Enter;
try
Result := FCount;
finally
FLock.Leave;
end;
end;
Operações Atômicas Nativas do FPC
{ InterlockedIncrement — operação atômica nativa }
InterlockedIncrement(FProcessedCount);
InterlockedDecrement(FPendingCount);
{ InterlockedExchange — troca atômica }
InterlockedExchange(FOldValue, LNewValue);
{ InterlockedCompareExchange — compare-and-swap }
InterlockedCompareExchange(FTarget, LNewVal, LExpectedVal);
Nota: No FPC são funções livres (
InterlockedIncrement), não métodos de classe (TInterlocked.Increment) como no Delphi.
TThreadList (Lista Thread-Safe)
var
FSharedList: TThreadList;
{ Thread A: adicionar }
LList := FSharedList.LockList;
try
LList.Add(LItem);
finally
FSharedList.UnlockList;
end;
{ Thread B: ler }
LList := FSharedList.LockList;
try
for I := 0 to LList.Count - 1 do
ProcessItem(LList[I]);
finally
FSharedList.UnlockList;
end;
TMultiReadExclusiveWriteSynchronizer (MREWS)
type
TThreadSafeCache = class
private
FData: TStringList;
FLock: TMultiReadExclusiveWriteSynchronizer;
public
constructor Create;
destructor Destroy; override;
function TryGet(const AKey: string; out AValue: string): Boolean;
procedure Put(const AKey, AValue: string);
end;
function TThreadSafeCache.TryGet(const AKey: string; out AValue: string): Boolean;
var
LIdx: Integer;
begin
FLock.BeginRead; // Múltiplas threads podem ler simultaneamente
try
LIdx := FData.IndexOfName(AKey);
Result := LIdx >= 0;
if Result then
AValue := FData.ValueFromIndex[LIdx];
finally
FLock.EndRead;
end;
end;
procedure TThreadSafeCache.Put(const AKey, AValue: string);
begin
FLock.BeginWrite; // Apenas uma thread pode escrever por vez
try
FData.Values[AKey] := AValue;
finally
FLock.EndWrite;
end;
end;
Eventos e Sinalização
TEvent
uses
syncobjs;
var
FStopEvent: TEvent;
{ Criar }
FStopEvent := TEvent.Create(nil, True, False, ''); // Manual reset, initially unsignaled
{ Thread: esperar sinal }
procedure TWorkerThread.Execute;
begin
while not Terminated do
begin
{ Esperar até 500ms por sinal de parada }
if FStopEvent.WaitFor(500) = wrSignaled then
Break;
{ Fazer trabalho }
DoWork;
end;
end;
{ Main thread: sinalizar parada }
FStopEvent.SetEvent;
Padrão Producer-Consumer (sem TThreadedQueue)
No FPC não existe TThreadedQueue<T>. Implementamos com TThreadList + TEvent:
type
TSimpleWorkQueue = class
private
FList: TThreadList;
FNewItemEvent: TEvent;
public
constructor Create;
destructor Destroy; override;
procedure Push(AItem: Pointer);
function Pop(ATimeoutMs: Cardinal): Pointer;
end;
constructor TSimpleWorkQueue.Create;
begin
inherited;
FList := TThreadList.Create;
FNewItemEvent := TEvent.Create(nil, False, False, '');
end;
destructor TSimpleWorkQueue.Destroy;
begin
FNewItemEvent.Free;
FList.Free;
inherited;
end;
procedure TSimpleWorkQueue.Push(AItem: Pointer);
var
LList: TList;
begin
LList := FList.LockList;
try
LList.Add(AItem);
finally
FList.UnlockList;
end;
FNewItemEvent.SetEvent; // Sinalizar que há item disponível
end;
function TSimpleWorkQueue.Pop(ATimeoutMs: Cardinal): Pointer;
var
LList: TList;
begin
Result := nil;
if FNewItemEvent.WaitFor(ATimeoutMs) = wrSignaled then
begin
LList := FList.LockList;
try
if LList.Count > 0 then
begin
Result := LList[0];
LList.Delete(0);
end;
finally
FList.UnlockList;
end;
end;
end;
Padrão: Background Worker com Callback
type
/// <summary>
/// Background worker genérico que executa trabalho pesado
/// e notifica a main thread via métodos sincronizados.
/// </summary>
TBackgroundWorkerThread = class(TThread)
private
FResult: string;
FError: string;
FOnSuccess: TNotifyEvent;
FOnError: TNotifyEvent;
procedure DoSuccess;
procedure DoError;
protected
procedure Execute; override;
function DoWork: string; virtual; abstract;
public
property OnSuccess: TNotifyEvent read FOnSuccess write FOnSuccess;
property OnError: TNotifyEvent read FOnError write FOnError;
property ResultValue: string read FResult;
property ErrorMessage: string read FError;
end;
procedure TBackgroundWorkerThread.Execute;
begin
try
FResult := DoWork;
if Assigned(FOnSuccess) then
Queue(@DoSuccess);
except
on E: Exception do
begin
FError := E.Message;
if Assigned(FOnError) then
Queue(@DoError);
end;
end;
end;
procedure TBackgroundWorkerThread.DoSuccess;
begin
if Assigned(FOnSuccess) then
FOnSuccess(Self);
end;
procedure TBackgroundWorkerThread.DoError;
begin
if Assigned(FOnError) then
FOnError(Self);
end;
Padrão: Timer Thread (Execução Periódica)
type
TTimerThread = class(TThread)
private
FInterval: Cardinal;
procedure DoTimerTick;
protected
procedure Execute; override;
procedure OnTick; virtual; abstract;
public
constructor Create(AIntervalMs: Cardinal);
end;
constructor TTimerThread.Create(AIntervalMs: Cardinal);
begin
inherited Create(True);
FreeOnTerminate := False;
FInterval := AIntervalMs;
end;
procedure TTimerThread.Execute;
begin
while not Terminated do
begin
Sleep(FInterval);
if not Terminated then
Synchronize(@DoTimerTick);
end;
end;
procedure TTimerThread.DoTimerTick;
begin
OnTick;
end;
Anti-Patterns a Evitar
// ❌ NUNCA acessar UI diretamente de thread secundária
procedure TMyThread.Execute;
begin
lblStatus.Caption := 'Processando...'; // CRASH ou comportamento imprevisível!
end;
// ✅ SEMPRE usar Synchronize/Queue para UI
procedure TMyThread.Execute;
begin
Queue(@DoUpdateLabel); // Seguro!
end;
// ❌ NUNCA criar thread com FreeOnTerminate=True e manter referência
FMyThread := TMyThread.Create(True);
FMyThread.FreeOnTerminate := True;
FMyThread.Start;
FMyThread.WaitFor; // CRASH! O objeto pode já ter sido liberado!
// ✅ Se precisa de WaitFor, NÃO use FreeOnTerminate
FMyThread := TMyThread.Create(True);
FMyThread.FreeOnTerminate := False;
FMyThread.Start;
FMyThread.WaitFor;
FMyThread.Free;
// ❌ NUNCA acessar variáveis compartilhadas sem proteção
Inc(FSharedCounter); // Race condition!
// ✅ SEMPRE proteger acesso compart
Truncated for display — read the full file on GitHub.
Related Skills
ai-job-search
45.3kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
claude-howto
41.8kA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
interview-me
102.0kExtracts what the user actually wants instead of what they think they should want. Achieves this through one-question-at-a-time interview until ~95% confidence about the underlying intent
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
