just a pretty crude snippet here as I was (not for the first time!) in need of the ability to dynamically create some threaded variables to be embedded within structures and the like and valid on all platforms.
More specifically, an app I am working on can have lots of instances of a certain structure kicking around, each of which can be accessed by multiple threads and I required a couple of fields in each structure variable to be 'threaded'. That is, for a given instance of the structure, whilst most fields remain the same for every thread, a couple of them can hold values unique to whichever thread is accessing them etc.
Loads of workarounds for this, but, well, here's mine! If someone finds it useful then, great. If not, that's ok as well!
Allows for integer values only, but easily modified to take any kind of value.
Code: Select all
CompilerIf Defined(INCLUDE_threadStorage, #PB_Constant)=0
#INCLUDE_threadStorage=1
;/////////////////////////////////////////////////////////////////////////////////
;threadStorage.
;==============
;
; Created with Purebasic 5.60 for Windows.
;
; Platforms: ALL.
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;NOTES.
;
; i) Dynamic creation of thread local storage.
; ii) The creation and deletion functions CreateThreadStorage()/DeleteThreadStorage() should really only be invoked from the main process.
; If they might be invoked from multiple threads then Mutex protection should be employed.
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;-MACROS.
;========
;The following allows us to define dynamic variables of type 'ThreadStorageIndex' for convenience.
Macro ThreadStorageIndex
i
EndMacro
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;-CONSTANTS and STRUCTURES.
;==========================
;The following constant determines how many possible indexes can be in use at any given time (this does not limit the number of threads).
;Change to a suitable value as appropriate.
#THREADSTORAGE_MAXNUMUSEDINDEXES = 1000
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;-GLOBAL and THREADED VARIABLES.
;===============================
Global Dim threadStorage_gUsedIndexes.i(#THREADSTORAGE_MAXNUMUSEDINDEXES)
Threaded Dim threadStorage_tIndexes.i(#THREADSTORAGE_MAXNUMUSEDINDEXES)
;/////////////////////////////////////////////////////////////////////////////////
;-FUNCTIONS.
;/////////////////////////////////////////////////////////////////////////////////
;The following creates a new thread storage index.
;Returns 0 if an error such as no more indexes available.
Procedure.i CreateThreadStorage()
Protected index, i
;Need to find the first free index.
For i = 1 To #THREADSTORAGE_MAXNUMUSEDINDEXES
If threadStorage_gUsedIndexes(i) = 0
;Mark it as used.
threadStorage_gUsedIndexes(i) = 1
index = i
Break
EndIf
Next
ProcedureReturn index
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;The following frees a thread storage index for reuse.
Procedure DeleteThreadStorage(index)
If index >0 And index <= #THREADSTORAGE_MAXNUMUSEDINDEXES
threadStorage_tIndexes(index) = 0
threadStorage_gUsedIndexes(index) = 0
EndIf
ProcedureReturn index
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;The following retrieves the value associated with the given 1-based thread storage index for the current thread.
Procedure.i GetThreadStorageValue(index)
If index >0 And index <= #THREADSTORAGE_MAXNUMUSEDINDEXES
;Only proceed if the index is in use.
If threadStorage_gUsedIndexes(index)
ProcedureReturn threadStorage_tIndexes(index)
EndIf
EndIf
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////
;/////////////////////////////////////////////////////////////////////////////////
;The following sets a value against the given 1-based thread storage index for the current thread.
Procedure SetThreadStorageValue(index, value)
If index >0 And index <= #THREADSTORAGE_MAXNUMUSEDINDEXES
;Only proceed if the index is in use.
If threadStorage_gUsedIndexes(index)
threadStorage_tIndexes(index) = value
EndIf
EndIf
EndProcedure
;/////////////////////////////////////////////////////////////////////////////////
CompilerEndIf
Code: Select all
;DEMO.
;=====
Global myTS.ThreadStorageIndex
Procedure thread(param)
;Set the value of our thread storage object for this thread.
SetThreadStorageValue(myTS, param*10)
For i = 1 To 100
Debug "Thread " + Str(param) + ", threadStorage value = " + Str(GetThreadStorageValue(myTS))
Delay(10)
Next
EndProcedure
myTS = CreateThreadStorage()
If myTS
;Set the value of our thread storage object for the main process.
SetThreadStorageValue(myTS, 1)
;Create a few threads.
th1 = CreateThread(@thread(), 1)
th2 = CreateThread(@thread(), 2)
th3 = CreateThread(@thread(), 3)
Repeat
Debug "Main process, threadStorage value = " + Str(GetThreadStorageValue(myTS))
Delay(10)
Until IsThread(th1) = 0 And IsThread(th2) = 0 And IsThread(th3) = 0
DeleteThreadStorage(myTS)
EndIf