Use cases

The TUF XOP aims to solve three distinct use cases which are currently not supported in stock Igor Pro:

Allow basic locking primitives for mutual exclusion

Allow preemptive threads to exchange data

The current implementation of thread queues for exchanging data in Igor Pro only allows to exchange data between the main thread and preemptive threads. But not between preemptive threads.

The TUF XOP allows that with the following steps:

  1. Create a storage space with TUFXOP_Init. This creates a wave reference wave with one point in memory.

  2. Get a reference from any thread to that wave reference wave via TUFXOP_GetStorage

  3. For sharing read-only data you are now done as no locking is involved. For writing data, be sure to use the locking primitives TUFXOP_AcquireLock and TUFXOP_ReleaseLock.

So in this case all threads can access the shared storage space:

digraph D {

    node [fontname="Arial"];

    rankdir = "RL";
    splines=line;

    block [shape=record label="{wave\nreference\nwave}"];

    thread1  [label="Thread 1"];
    thread2  [label="Thread 2"];
    thread3  [label="Thread 3"];
    threadX  [label="Thread X"];

    thread1  -> block;
    thread2  -> block;
    thread3  -> block;
    threadX  -> block;
}

It is important to mention again that the user is responsible for ensuring that the threads don’t overwrite each others data!

Storing data from threadsafe functions called via MultiThread

When a threadsafe function is called via MultiThread there is currently no way it can permanently store data in memory. The TUF XOP implements thread-local storage which can be accessed concurrently via:

  1. Create a storage space with TUFXOP_Init. This creates a wave reference wave with one point in memory.

  2. Get a reference to a per-thread wave reference wave via TUFXOP_GetStorage and its /TS flag. As the returned wave reference wave is different for each thread there is no need to lock for writing.

  3. Once you are done, you can get all thread-local storage with TUFXOP_GetStorage but this time without passing /TS.

Here each thread only sees one entry of the wave reference wave, namely that which is reserved for that thread alone:

digraph D {

    node [fontname="Arial"];

    rankdir = "LR";
    splines=line;

    block [shape=record, label="{{<d1> index 0 | <d2> index 1 | <d3> index 2 | <dX> ...} | wave\nreference\nwave}"];

    thread1  [label="Thread 1"];
    thread2  [label="Thread 2"];
    thread3  [label="Thread 3"];
    threadX  [label="Thread X"];

    thread1 -> block:d1;
    thread2 -> block:d2;
    thread3 -> block:d3;
    threadX -> block:dX;
}