DEV Community

Odd_Background_328
Odd_Background_328

Posted on

Put a Coding Agent's Parallel Sub-Tasks Behind a Deadlock Detector, Not a Hope

Anthropic's Claude Sonnet 4.6 can spawn up to eight parallel sub-agents in a single session. OpenAI's GPT-5.2-codex runs flat tool loops. GitHub's Copilot Workspace splits planning from execution. All three architectures create the same operational risk: when multiple parallel tasks modify shared resources, your system needs a concurrency invariant, not a dashboard.

Why parallel sub-agents break production

A parent agent that spawns eight sub-agents is not running eight independent jobs. It is running eight writers that may target the same file, the same database row, or the same deployment target. Without a coordination layer, the last writer wins and the others silently fail.

A deadlock detector you can run locally

This fixture simulates a parent agent dispatching parallel sub-tasks that compete for a shared resource:

# deadlock_detector.py
"""
Simulates parallel agent sub-tasks competing for a shared resource
and detects whether the coordination layer serializes correctly.
"""
import threading
import time
import json

class SharedResource:
    def __init__(self):
        self.lock = threading.Lock()
        self.write_log = []
        self.conflict_count = 0

    def safe_write(self, task_id, payload):
        with self.lock:
            self.write_log.append({
                "task": task_id,
                "payload": payload,
                "timestamp": time.time()
            })
            return True

    def unsafe_write(self, task_id, payload):
        # No lock - race condition
        current_len = len(self.write_log)
        time.sleep(0.001)  # Simulate processing delay
        self.write_log.append({
            "task": task_id,
            "payload": payload,
            "timestamp": time.time()
        })
        if len(self.write_log) != current_len + 1:
            self.conflict_count += 1
        return True

def run_parallel_tasks(resource, num_tasks=8, safe=True):
    write_fn = resource.safe_write if safe else resource.unsafe_write
    threads = []
    for i in range(num_tasks):
        t = threading.Thread(
            target=write_fn,
            args=(f"subagent-{i}", f"change-{i}")
        )
        threads.append(t)
        t.start()
    for t in threads:
        t.join()
    return resource.write_log

if __name__ == "__main__":
    # Test unsafe path
    unsafe_res = SharedResource()
    run_parallel_tasks(unsafe_res, safe=False)
    print(f"Unsafe: {len(unsafe_res.write_log)} writes, {unsafe_res.conflict_count} conflicts")

    # Test safe path
    safe_res = SharedResource()
    run_parallel_tasks(safe_res, safe=True)
    print(f"Safe: {len(safe_res.write_log)} writes, {safe_res.conflict_count} conflicts")

    # Invariant: all writes must be present and conflict-free
    assert len(safe_res.write_log) == 8, "Missing writes!"
    assert safe_res.conflict_count == 0, "Conflicts detected!"
    print("PASS: safe coordination serialized all writes")
Enter fullscreen mode Exit fullscreen mode

What this tests

Property Unsafe path Safe path
All writes present May lose writes under contention All writes recorded
Write order Non-deterministic Serialized by lock
Conflict detection None Counter increments
Replay capability Unreliable log Append-only log

The operational question

When a coding agent spawns parallel sub-tasks, which of these invariants does your system enforce?

  1. Mutual exclusion: only one sub-task modifies a shared file at a time
  2. Monotonic log: every write is durably recorded in order
  3. Conflict detection: the system knows when two sub-tasks targeted the same resource
  4. Rollback path: a failed sub-task's writes can be identified and reverted

If you cannot answer all four, the parallel sub-agent architecture is running on hope, not a protocol.

Limitations

  • This fixture uses threads, not processes. Real agent sub-tasks run in separate containers or sessions with network latency.
  • The lock model assumes a single coordinator. Distributed coordination requires a different protocol (e.g., optimistic locking with version vectors).
  • The fixture does not test deadlocks caused by circular dependencies between sub-tasks.

What to check

Before enabling an eight-sub-agent workflow on your repository, run this fixture and verify that your CI system can detect a write conflict. If it cannot, reduce the parallelism to one sub-task until it can.

Top comments (0)