Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works
Anything · Lazarus or Delphi
Random projectRandom project

threadsafecollections-fp

A thread-safe generic collections library for Free Pascal.

View on GitHub

Member rating

No ratings yet.

Sign in to rate this project.

README

ThreadSafeCollections-FP — concurrent collections for Free Pascal

ThreadSafeCollections-FP

Thread-safe generic lists, deques, dictionaries, and hash sets for Free Pascal.

ThreadSafeCollections-FP provides familiar collection APIs with per-instance synchronization, bulk operations, and documented iteration behavior. It is a learning-focused project with a tested core, runnable examples, and no required packages beyond the Free Pascal standard distribution.

Documentation

The online documentation site — including installation, guides for every collection, recipes, an API cheat sheet, full-text search, and versioned releases — is published at:

https://ikelaiah.github.io/threadsafecollections-fp/

Repository-local documentation lives under docs/; start at docs/start/index.md.

[!IMPORTANT] The library is intended for learning and experimentation. Evaluate its behavior, performance, and test coverage against your application's requirements before adopting it in production.

Start Here

Your goal Best starting point
See it work in five minutes Five-minute first run
Add it to a Free Pascal or Lazarus project Installation
Learn the collection APIs Feature tour and API cheat sheet
Understand locking and iteration Thread-safety model
Build examples, tests, or generated docs Building and verification
Browse guides, recipes, and the API reference Online documentation
See planned compatibility and API work Roadmap

Five-minute first run

You need Free Pascal (fpc) on your PATH. The commands below compile the existing number-list example directly from source and keep all generated files under build-temp/.

Clone the repository:

text
git clone https://github.com/ikelaiah/threadsafecollections-fp.git
cd threadsafecollections-fp

On Windows PowerShell:

powershell
New-Item -ItemType Directory -Force build-temp\first-run\units, build-temp\first-run\bin | Out-Null
fpc -B -Fusrc -FUbuild-temp\first-run\units -FEbuild-temp\first-run\bin examples\SimpleNumberList\SimpleNumberList.lpr
.\build-temp\first-run\bin\SimpleNumberList.exe

On Linux with Bash:

bash
mkdir -p build-temp/first-run/units build-temp/first-run/bin
fpc -B -Fusrc -FUbuild-temp/first-run/units -FEbuild-temp/first-run/bin examples/SimpleNumberList/SimpleNumberList.lpr
./build-temp/first-run/bin/SimpleNumberList

The program prints ten random integers, sorts them in both directions, and waits for Enter before exiting. The Windows commands and example were verified with FPC 3.2.2 on Win64. The same Bash build path is exercised for all examples by Linux CI. The maintained target platforms are Windows x86-64 and Linux; macOS is not currently targeted or tested.

Installation

Requirements

  • Free Pascal Compiler. FPC 3.2.2 is the version used for the maintained local test snapshot.
  • A Free Pascal installation containing SyncObjs (from fcl-base) and Generics.Collections (from rtl-generics). Both are standard units included in the tested FPC 3.2.2 distribution; they are not third-party dependencies.
  • The Lazarus package metadata separately declares the FCL package as a requirement.
  • Lazarus is optional. The package build for this documentation revision was verified locally with Lazarus 4.8.
  • Windows CI installs Lazarus 4.0.0 to obtain its bundled FPC, then compiles the examples directly with fpc; it does not invoke lazbuild or build the Lazarus package.
  • Git and PowerShell are needed only for the corresponding clone, build, or documentation-generator workflows.

There are no required third-party Pascal packages.

Use the source units directly

Add this repository's src directory to your compiler's unit search path. From the repository root, -Fusrc does that for a command-line build:

text
fpc -Fusrc path/to/YourProgram.lpr

In Lazarus, add src to Project Options > Compiler Options > Paths > Other unit files, or install/open package/lazarus/ThreadSafeCollections.lpk and add the package as a project requirement.

The library units use dotted names:

pascal
uses
  ThreadSafeCollections.List,
  ThreadSafeCollections.Deque,
  ThreadSafeCollections.Dictionary,
  ThreadSafeCollections.HashSet;

Import only the units your program needs.

Your first collection

This complete program creates an integer list, adds values, sorts them, and prints the result:

pascal
program FirstThreadSafeList;

{$mode objfpc}{$H+}{$J-}

uses
  ThreadSafeCollections.List;

var
  Numbers: specialize TThreadSafeList<Integer>;
  Number: Integer;
begin
  Numbers := specialize TThreadSafeList<Integer>.Create(@IntegerComparer);
  try
    Numbers.AddRange([30, 10, 20]);
    Numbers.Sort;

    for Number in Numbers do
      WriteLn(Number);
  finally
    Numbers.Free;
  end;
end.

Save it as build-temp/first-list/FirstThreadSafeList.lpr, then compile it with the same -Fusrc, -FU, and -FE pattern used in the first-build commands.

Free Pascal orientation

If Free Pascal generics are new to you, these are the conventions used above:

  • {$mode objfpc} selects the language mode used throughout this repository.
  • uses imports units. Unit filenames and paths must keep their exact casing on case-sensitive filesystems.
  • specialize turns a generic type such as TThreadSafeList<T> into a concrete type such as TThreadSafeList<Integer>.
  • @IntegerComparer passes the comparison function needed for list searching and sorting. Custom element types need a comparer with the same signature.
  • Classes are explicitly freed. try..finally ensures Free runs if an operation raises an exception.
  • Interface-backed collections use reference counting instead; see examples/InterfaceTest.
  • A threaded Unix program should place cthreads first in its program uses clause before it creates threads. The chat and benchmark examples demonstrate this pattern.

Feature tour

List

TThreadSafeList<T> is a resizable array with indexed access, add/insert/delete operations, ranges, sorting, searching, reversing, moving, array conversion, and capacity management. It requires a comparer at construction.

List guide · Simple example

Deque

TThreadSafeDeque<T> is a circular-buffer double-ended queue. It supports push, pop, peek, and Try* operations at both ends, plus range and array operations.

Deque guide · Simple example

Dictionary

TThreadSafeDictionary<TKey, TValue> stores key/value pairs in chained hash buckets. It supports add, update, lookup, removal, bulk operations, key/value snapshots, and custom hash and equality functions.

Dictionary guide · Iterator example

Hash set

TThreadSafeHashSet<T> stores unique values and supports single-item and bulk updates, lookup, removal, intersection, union, difference, overlap checks, and set equality. Specialized integer, string, Boolean, and real set classes provide built-in hash/equality choices.

Hash-set guide · Client example

Interfaces and lock tokens

Each collection has an interface form, and Lock returns an interface token that releases the collection lock when the token leaves scope. The implementation uses these tokens for lock-holding enumerators and dictionary snapshot creation. Because public methods acquire the same lock themselves, do not hold a manual token and then call public methods on that collection; this can deadlock on non-reentrant implementations.

RAII-style locking guide · Interface example

Thread-safety model

Each collection instance owns one TCriticalSection. Public collection operations synchronize access to that instance.

That boundary matters:

  • One method call is synchronized; a check followed by a separate update is not automatically one atomic operation. Prefer a combined operation such as TryAdd, AddOrSetValue, or TryPop* where applicable, or coordinate the sequence with external synchronization you control.
  • List, deque, and hash-set for..in enumerators retain the collection lock for the enumerator's lifetime. Keep loop bodies short and do not hand an enumerator to another thread.
  • Dictionary iteration snapshots the pairs first, then releases the dictionary lock. The snapshot does not reflect later updates.
  • Synchronization protects collection structure, not mutable objects referenced by stored pointers, classes, or interfaces.
  • Class instances stored as elements are not automatically freed by the collection.
  • A collection must outlive every thread, enumerator, and lock token using it.

The implementation uses mutual exclusion; it is not a lock-free or reader/writer-lock design. The iterator difference between lock-holding (List, Deque, HashSet) and snapshot (Dictionary) enumeration is an intentional, tested policy documented in Thread-safety, iteration, and lock policy.

Supported and verified environments

Environment What is verified
Windows x86-64, FPC 3.2.2 Current 175-test FPCUnit run with HeapTrc, documented examples, and both all-example scripts
Windows x86-64, Lazarus 4.8 Command-line build of the Lazarus package and the package smoke consumer
Windows CI (windows-latest), FPC bundled with Lazarus 4.0.0 All tracked examples compile and the full FPCUnit suite, including the concurrency, deadlock, and stress suites, runs through the PowerShell test script
Linux CI (ubuntu-latest) All tracked examples compile with the distribution FPC package, the full FPCUnit suite runs, the Lazarus package builds with lazbuild, and the documentation checks pass
macOS and other FPC targets Out of scope for now; the maintained focus is Windows x86-64 and Linux

The source is written for FPC's objfpc mode. A platform being supported by FPC does not by itself mean this repository has tested that platform.

Build, test, benchmark, and generated docs

The repository includes scripts to compile every example:

powershell
.\build-examples.ps1 -Configuration Release
bash
./build-examples.sh Release

Valid configurations are Debug and Release; omitting the value selects Release. The scripts place programs in example-bin/.

The FPCUnit suite, benchmark options, Lazarus package build, and cheat-sheet generator have separate commands and prerequisites. Follow Building and verification for their exact scope. The same test, package-smoke, and documentation-check commands that CI runs are available locally through run-tests.*, smoke-package.*, and tools/check-*.ps1.

Example learning path

  1. SimpleNumberList — generic specialization, a comparer, indexed access, and sorting.
  2. SimpleDeque — front/back queue operations and TryPop.
  3. SimpleHashSet — uniqueness, membership, removal, and specialized set types.
  4. DictionaryIterator — snapshot iteration with Generics.Collections.TPair.
  5. SimpleShoppingCart — records and a custom comparer.
  6. ChatMessageQueue — a multi-threaded queue demonstration; stop it with Ctrl+C.

All 16 tracked examples and their build status are listed in the building guide.

Contributing

Bug reports, focused changes, tests, examples, and documentation improvements are welcome. Before proposing a change, build the affected examples and run the relevant tests described in Building and verification.

License

ThreadSafeCollections-FP is available under the MIT License.

🙏 Acknowledgments