Chapter 36 Key Takeaways
TThread Essentials
- Subclass
TThread, overrideExecute Create(True)= suspended; callStartto beginTerminatesetsTerminated := True— a polite request, not a kill- Check
Terminatedperiodically in yourExecuteloop WaitForblocks until the thread finishesFreeOnTerminate := True= auto-freed (do not access the object after Start)
The Golden Rule
If two threads can access the same data, and at least one writes, you MUST synchronize access. No exceptions.
GUI Updates
- Never access GUI controls from a worker thread
Synchronize(@Method)— blocks worker until main thread executesQueue(@Method)— non-blocking, main thread executes later (preferred)
TCriticalSection
Lock.Enter;
try
{ Protected code — only one thread at a time }
finally
Lock.Leave; { ALWAYS in a finally block }
end;
- One thread at a time inside the Enter/Leave block
- Other threads block at
Enteruntil the first callsLeave - Always use
try..finally— exceptions must not leave the lock held
Thread-Safe Data Structures
- Encapsulate a
TCriticalSectioninside the data structure - Lock every method that reads or writes shared fields
- Use the snapshot pattern for iteration: lock, copy, unlock, iterate copy
Thread Pool Pattern
- Fixed set of worker threads + shared work queue
- Avoids thread creation overhead for many tasks
- Workers loop: dequeue, process, repeat until terminated
Common Bugs
| Bug | Cause | Prevention |
|---|---|---|
| Race condition | Unprotected shared data | Always lock shared mutable data |
| Deadlock | Circular lock dependencies | Always acquire locks in the same order |
| Starvation | Unfair resource access | Use fair locks, limit hold times |
| Leaked lock | Exception between Enter/Leave | Always use try..finally |
PennyWise Background Sync
TBackgroundSyncthread runs continuously, syncing every 30 seconds- Pending expenses queued via
QueueExpense(protected by critical section) - Status updates via
Queue(non-blocking GUI update) - Failed syncs re-queue the expense for retry
- Cooperative termination via
Terminatedcheck