Cairo context corruption when shared across threads without external locking
0 reputation · 04 Jul 2020, 11:51 UTC
Concurrent rendering with shared cairo_t
The goal is to enable safe concurrent drawing operations on a single Cairo surface from multiple threads. Cairo's documented contract treats cairo_t as single-threaded; the mutable path, source, and transformation state inside the context have no internal synchronization and assume exclusive access. While cairo_surface_t reference counting is thread-safe, sharing a context across threads without external locking produces undefined behavior that manifests as rendering artifacts, memory corruption, or crashes depending on the backend.
Constraints include the absence of a lock parameter or runtime error for concurrent context misuse, backend-specific tolerance for accidental sharing that varies across platforms, and the performance cost of serializing all drawing work behind a global mutex. Using separate cairo_t instances per thread on the same surface avoids context-state races but may still introduce surface-memory races unless the specific backend guarantees thread-safe rasterization.
What synchronization strategy preserves correctness across backends without serializing unrelated drawing work? Does creating one cairo_t per thread on a shared image surface eliminate all data races, or do surface-level races persist? Are there backend-specific guarantees for thread-safe rasterization that can be relied upon in production?