Stateful Goroutines in Scilab

Our example demonstrates how to manage state using a single thread (in Scilab, we don’t have goroutines) and message passing. This approach aligns with the idea of sharing memory by communicating and having each piece of data owned by exactly one thread.

// In this example our state will be owned by a single thread. This will guarantee 
// that the data is never corrupted with concurrent access. In order to read or 
// write that state, other threads will send messages to the owning thread and 
// receive corresponding replies. These readOp and writeOp structures encapsulate 
// those requests and a way for the owning thread to respond.

function [value] = readOp(key)
    value = state(key);
endfunction

function writeOp(key, val)
    state(key) = val;
endfunction

// Initialize the state
state = struct();

// As before we'll count how many operations we perform.
readOps = 0;
writeOps = 0;

// This function simulates the state-owning thread
function stateManager()
    while %T
        // In Scilab, we don't have a built-in select statement for channels
        // So we'll simulate it with a simple if-else structure
        if ~isempty(reads)
            key = reads(1);
            reads(1) = [];
            respq($+1) = readOp(key);
        elseif ~isempty(writes)
            [key, val] = writes(1);
            writes(1) = [];
            writeOp(key, val);
            respq($+1) = %T;
        end
    end
endfunction

// Start the state manager in a separate thread
execstr('stateManager()', 'errcatch', 'n');

// Simulate multiple read operations
for i = 1:100
    execstr(['
        while %T
            key = floor(rand() * 5) + 1;
            reads($+1) = key;
            response = respq(1);
            respq(1) = [];
            readOps = readOps + 1;
            sleep(1);
        end
    '], 'errcatch', 'n');
end

// Simulate multiple write operations
for i = 1:10
    execstr(['
        while %T
            key = floor(rand() * 5) + 1;
            val = floor(rand() * 100) + 1;
            writes($+1) = [key, val];
            response = respq(1);
            respq(1) = [];
            writeOps = writeOps + 1;
            sleep(1);
        end
    '], 'errcatch', 'n');
end

// Let the threads work for a second.
sleep(1000);

// Finally, capture and report the op counts.
disp("readOps: " + string(readOps));
disp("writeOps: " + string(writeOps));

Running our program shows that the thread-based state management example completes a certain number of total operations.

readOps: 71708
writeOps: 7177

For this particular case, the thread-based approach in Scilab is quite different from the original example due to language limitations. Scilab doesn’t have built-in support for goroutines or channels, so we’ve simulated the behavior using Scilab’s threading capabilities and global variables for communication.

This approach might be useful in certain cases, especially when dealing with shared state in a multi-threaded environment. However, it’s important to note that Scilab’s threading model is different from Go’s, and this implementation doesn’t provide the same level of concurrency control.

You should use whichever approach feels most natural and is most appropriate for your specific use case in Scilab, especially with respect to understanding the correctness of your program.