---
title: Generating Unique IDs Safely Across Threads
slug: generating-unique-ids-safely-across-threads
docTags: 
createdAt: 2026-03-19T02:39:12.957Z
---

### Overview

Use a shared parameter and increment it with InterlockIncrement to generate IDs without collisions across concurrent threads. This method delegates the increment to a stored procedure, which makes the update atomic at the database level rather than relying on in-memory script logic.

### Applies To

- Scripts that generate sequential IDs&#x20;
- Environments where multiple threads may request a new ID at the same time&#x20;
- Parameters stored in the provisioning system and backed by SQL&#x20;

### Problem

When multiple threads read and increment the same value independently, two or more threads can read the same current value before any of them writes the next one. This creates duplicate IDs.

### Cause

A standard read-update-write sequence is not safe under concurrency. The value must be incremented in a single atomic operation that all threads share.

### Resolution

Store the last issued ID in a shared parameter and call InterlockIncrement on that parameter whenever a new ID is needed.

```csharp
Parameter p = Parent.GetLocalParameter("LastId");
int i = Convert.ToInt32(p.Value);
p.InterlockIncrement(10000); // 10000 is the maximum possible value
Trace.WriteLine(i.ToString());
```

### How It Works

InterlockIncrement does not simply add one in script memory. It calls a SQL stored procedure named ParameterIncrement and passes:

- @ParameterID to identify the parameter being incremented&#x20;
- @MaxValue to define the maximum allowed value&#x20;

The stored procedure returns the updated parameter value and timestamp, which are then written back to the in-memory object.

Relevant behavior from the method:

- Opens a new SQL connection&#x20;
- Executes ParameterIncrement as a stored procedure&#x20;
- Reads the updated value from the result set&#x20;
- Updates the parameter timestamp&#x20;
- Closes the reader and connection in finally&#x20;
- Wraps failures in Unable to increment parameter&#x20;

This means the increment is coordinated through the database, which is what provides thread safety across concurrent script execution.

### Important Behavior

The example reads the parameter value before calling InterlockIncrement:

```csharp
int i = Convert.ToInt32(p.Value);
p.InterlockIncrement(10000);
```

That means i contains the value before the increment. In practice:

- i is the ID being issued for the current request&#x20;
- InterlockIncrement advances the stored counter so the next thread gets a different value&#x20;

This pattern works only if all threads use the same shared parameter and all increments go through InterlockIncrement.

### Step-by-Step

1. Create or identify a shared parameter such as LastId.&#x20;
2. Retrieve the parameter in script.&#x20;
3. Read the current value and use it as the next unique ID.&#x20;
4. Immediately call InterlockIncrement(MaxValue) to advance the shared counter atomically.&#x20;
5. Persist or log the issued ID as needed.&#x20;

### Example

```csharp
Parameter p = Parent.GetLocalParameter("LastId");

int nextId = Convert.ToInt32(p.Value);

p.InterlockIncrement(10000);

Trace.WriteLine(nextId.ToString());
```

### Notes on MaxValue

MaxValue is passed to the stored procedure and defines the upper limit for the parameter. The exact behavior at that limit depends on the implementation of ParameterIncrement. Verify whether it:

- wraps back to a starting value&#x20;
- stops incrementing&#x20;
- throws an error&#x20;

Do not assume rollover behavior unless it is confirmed in the stored procedure logic.

### Error Handling

If the increment fails, the method throws:

:::BlockQuote
throw new Exception("Unable to increment parameter", ex);
:::

Handle this in calling code if ID generation is critical to the workflow.

### Additional Notes

- This approach is safe for concurrent threads because the increment is handled centrally in SQL.&#x20;
- Do not replace InterlockIncrement with a manual p.Value = ... update in multi-threaded scenarios.&#x20;
- Ensure every thread uses the same parameter name and same increment path.&#x20;
- If uniqueness must extend beyond a single shared counter scope, use separate namespaces or prefixes in addition to the numeric ID.
