# Race safety and AL0202

> Understand which concurrent captures Alice rejects and how to write safe parallel work.

Canonical: https://alice-lang.org/documentation/concurrency/race-safety/

[Documentation index](https://alice-lang.org/documentation/llms.txt) · [Complete book](https://alice-lang.org/llms-full.txt)

## The rule

Alice rejects writes that can race in recognized concurrent contexts: `spawn`, `Par.For`, `par_each`, `Task.Run` lambdas, and actor handlers. The compiler's race model also gates automatic parallelization. Code is not automatically parallelized unless it is proven eligible and pure.

## A rejected accumulator

```alice
# Does not compile: AL0202
sum = 0
Par.For(100) { |i| sum += i }
```

Every worker can read and overwrite the same scalar. The result would depend on timing. Moving the write into a method that mutates an instance field does not hide it from the race model.

## Safe communication

```alice
counter = Atomic.new(0)
Par.For(1000) { |i| counter.add(1) }
puts counter.get
```

Expected output:

```text
1000
```

[Edit and run in the Alice playground](https://playground.alice-lang.org/#code=u.Y291bnRlciA9IEF0b21pYy5uZXcoMCkKUGFyLkZvcigxMDAwKSB7IHxpfCBjb3VudGVyLmFkZCgxKSB9CnB1dHMgY291bnRlci5nZXQ)

For a more general reduction, return values from tasks, use a reduction helper, or send values through a channel to one consumer. Use a mutex when the update must cover an object with several related fields.

## Allowed and rejected patterns

| Pattern                                                  | Result                                   |
| -------------------------------------------------------- | ---------------------------------------- |
| Read a captured value                                    | Allowed                                  |
| Assign or compound-assign a captured local               | Rejected                                 |
| Mutate a captured ordinary collection                    | Rejected                                 |
| Write `array[i]` at disjoint worker indices in `Par.For` | Supported                                |
| Write `array[0]` from every worker                       | Rejected                                 |
| Mutate `@field` in a concurrently called method          | Rejected when identified by the analysis |
| Use `Mutex(T).lock`, `Atomic`, `Channel`, or `Actor`     | Supported synchronization/communication  |
| Use supported `Interlocked` operations                   | Supported                                |
| Use `System.Collections.Concurrent` collections          | Recognized concurrent APIs               |
| Use `Volatile.Write` as a substitute for synchronization | Rejected                                 |

A disjoint index must actually be disjoint. Do not reuse worker indices modulo a smaller array and assume they describe independent destinations.

## Automatic parallelism

Pure array pipelines and eligible counted loops can get parallel paths above workload thresholds. Impure callbacks, I/O, unknown effects, order-dependent writes, and unsafe captures prevent that transformation. Small workloads normally stay serial to avoid scheduling overhead.

Parallel floating-point reductions can reassociate addition. Race safety does not imply bit-identical floating-point output across every execution strategy.

## Scope of the guarantee

The analysis covers recognized Alice constructs and effect models. Reflection, arbitrary foreign libraries, external processes, and unsafe APIs can have effects outside that model. Do not treat a successful compilation as a proof about an unmodeled external API's behavior. Keep shared-state boundaries explicit and test application-level ordering and lifecycle rules.

## Continue reading

- Previous: [Mutexes and atomics](https://alice-lang.org/documentation/concurrency/synchronization.md)
- Next: [Use .NET and NuGet](https://alice-lang.org/documentation/guides/dotnet.md)
