Expand/Shrink

thread_safe_string

Definition: string res = thread_safe_string(string s)
Description: Create a thread-safe version of the passed string.
pwa/p2js: Not supported.
Comments: Effectively creates a private reference count that the thread can freely incref and decref without locking.

Result is only thread safe when it is stored in a variable that only one thread uses.

As you can see below, there are many possible variations: you just need to choreograph a dance whereby no-one steps on anybody else’s toes. As mentioned previously, one of the hardest things about using multithreading in Phix is figuring out where these hidden reference counts are, and ensuring they are not shared/updated in an unsafe fashion.
Example 1:
constant string FLOAT = thread_safe_string("%f") -- for use in process_ticker() only

procedure process_ticker()
    atom {{price}} = scanf(pricestr,FLOAT)
    ...
end procedure

atom hThread = create_thread(process_ticker,{})

The above assumes only one instance of process_ticker is initiated, however the main thread and other background threads may be using "%f", but that must not be the same one (refcount) being used here (and as coded isn’t).
Example 2:
procedure process_ticker(string fltfmt)
    atom {{price}} = scanf(pricestr,fltfmt)
    ...
end procedure

for i=1 to MAX_TICKERS do
    atom hThread = create_thread(process_ticker,{thread_safe_string("%f")})
end for

This allows you to create multiple process_ticker threads, and give each one a thread-safe "%f".
Example 3:
constant string FLOAT = thread_safe_string("%f") -- a lockable version
constant fltcs = init_cs()

procedure process_ticker()
    enter_cs(fltcs)
    string fltfmt = thread_safe_string(FLOAT)
    leave_cs(fltcs)
    ...
    atom {{price}} = scanf(pricestr,fltfmt)
    ...
end procedure

for i=1 to MAX_TICKERS do
    atom hThread = create_thread(process_ticker,{})
end for

This allows multiple process_ticker threads, with each one creating its own thread-safe copy.
Note that the main thread may be using "%f" while a background thread is trying to make a copy of it (mess with its refcount), hence the lockable version. There are some subtleties here, especially with that top-level call: a plain "%f" is a pooled constant that can be used anywhere in the application and you have no say whatsoever over that. The more local FLOAT is intended to only ever be used inside that critical section. The more private and genuinely thread safe fltfmt belongs entirely to the single thread that created it. It would of course be entirely reasonable not to have fltfmt as long as process_ticker() only ever uses FLOAT under cover of fltcs (but would put all of scanf() under it too).
Lastly note how the unprotected thread_safe_string() is perfectly safe inside the create_thread() call of example 2, but such would not be safe in the code of a thread itself.

Similar situations arise for thread safe floats, though Phix does not as yet have a thread_safe_atom() routine.
Integers are always copied by value and never have a reference count, so no need to worry about them.
Containing [nested] sequences are (kinda) covered by deep_copy() though, again, there is not as yet a routine that ties them all together. I foresee no difficulties, aside perhaps from giving it a clear and intuitive name, or adding the ideal additional parameter to deep_copy(), but would rather have a real-world example that actually needs and can test it.
It might well/just be that Phix deserves a thread_safe() that can deal with anything (instead of this string-only thing).
Implementation: See builtins\VM\pThreadN.e (an autoinclude) for details of the actual implementation.
See Also: create_thread