Mutexes in UnrealScript

In the previous example we saw how to manage simple counter state using atomic operations. For more complex state we can use a mutex to safely access data across multiple threads.

class MutexExample extends Object;

struct Container
{
    var transient Lock Mutex;
    var map<string, int> Counters;
};

function Increment(out Container C, string Name)
{
    C.Mutex.Lock();
    C.Counters[Name]++;
    C.Mutex.Unlock();
}

function ExecuteTest()
{
    local Container C;
    local int i;
    
    C.Mutex = new class'Lock';
    C.Counters = new class'Map<string, int>';
    C.Counters.Add("a", 0);
    C.Counters.Add("b", 0);
    
    // Simulate concurrent access using a loop
    for (i = 0; i < 10000; i++)
    {
        Increment(C, "a");
        Increment(C, "a");
        Increment(C, "b");
    }
    
    `log("Counters: a=" $ C.Counters["a"] $ ", b=" $ C.Counters["b"]);
}

DefaultProperties
{
}

In this example, we define a Container struct that holds a map of counters. Since we want to update it concurrently from multiple threads, we add a Lock (UnrealScript’s equivalent of a mutex) to synchronize access.

The Increment function locks the mutex before accessing Counters, and unlocks it at the end of the function. This ensures that only one thread can modify the counters at a time.

In the ExecuteTest function, we create a new Container and initialize its counters. We then simulate concurrent access by calling Increment in a loop. In a real scenario, you might use UnrealScript’s native multithreading capabilities to achieve true concurrency.

Note that UnrealScript doesn’t have built-in support for goroutines or wait groups. Instead, we’re using a simple loop to simulate concurrent access. In a real UnrealEngine game, you might use the engine’s task system or timer functions to achieve similar results.

Running this code would produce output similar to:

Counters: a=20000, b=10000

This demonstrates that the counters were updated as expected, with proper synchronization preventing race conditions.

Remember that in UnrealScript, you typically wouldn’t run this kind of code directly. Instead, you’d integrate it into your game logic, perhaps as part of an Actor or GameMode class.

In the next example, we might look at implementing similar state management using UnrealScript’s event system or the engine’s built-in multithreading capabilities.