From e28a73ef1ce55442b729643106b0c2c917af05e4 Mon Sep 17 00:00:00 2001 From: Michael Huth Date: Wed, 21 Aug 2024 18:15:01 +0200 Subject: [PATCH] TSDS: Revision of ThreadSafeDataStorage utility functions - cleaner API with public ReadVar / WriteVar and private Create / Storage Getter - writing a variable now does not reinitializes the named storage causing an additional release of two waves and a recreation of two waves. Due to memory allocation each wave creation causes a global lock. - fixes the mixed if check of data/wv in Line 63 - adapted tests --- Packages/MIES/MIES_Debugging.ipf | 2 +- Packages/MIES/MIES_ThreadsafeDataSharing.ipf | 73 +++++++++++-------- Packages/tests/Basic/UTF_Debugging.ipf | 6 -- .../tests/Basic/UTF_ThreadsafeDataSharing.ipf | 60 ++++++++------- Packages/tests/UTF_HelperFunctions.ipf | 6 +- 5 files changed, 78 insertions(+), 69 deletions(-) diff --git a/Packages/MIES/MIES_Debugging.ipf b/Packages/MIES/MIES_Debugging.ipf index 639465437e..b33dda1bb4 100644 --- a/Packages/MIES/MIES_Debugging.ipf +++ b/Packages/MIES/MIES_Debugging.ipf @@ -600,7 +600,7 @@ threadsafe Function BUG_TS(string msg, [WAVE/T keys, WAVE/T values]) TUFXOP_AcquireLock/N=(TSDS_BUGCOUNT) bugCount = TSDS_ReadVar(TSDS_BUGCOUNT, defValue = 0, create = 1) bugCount += 1 - TSDS_Write(TSDS_BUGCOUNT, var = bugCount) + TSDS_WriteVar(TSDS_BUGCOUNT, bugCount) TUFXOP_ReleaseLock/N=(TSDS_BUGCOUNT) print "BUG_TS: Should never be called during automated testing." diff --git a/Packages/MIES/MIES_ThreadsafeDataSharing.ipf b/Packages/MIES/MIES_ThreadsafeDataSharing.ipf index 56939c0d4b..200d5089d7 100644 --- a/Packages/MIES/MIES_ThreadsafeDataSharing.ipf +++ b/Packages/MIES/MIES_ThreadsafeDataSharing.ipf @@ -10,59 +10,70 @@ /// /// @brief Helper functions for accessing global objects from all threads -threadsafe Function TSDS_Write(string name, [variable var]) - ASSERT_TS(!ParamIsDefault(var), "Missing var parameter") +/// @brief Creates/Overwrites a threadstorage and puts a numerical value in +threadsafe static Function TSDS_Create(string name, variable var) + ASSERT_TS(!IsEmpty(name), "name can not be empty") - TUFXOP_Init/N=name/Z - TUFXOP_GetStorage/N=name/Z wv + TUFXOP_Init/Z/N=name + TUFXOP_GetStorage/Z/N=name wv - Make/FREE/N=(1)/D data = var + Make/FREE/D data = {var} wv[0] = data End +/// @brief Reads a numerical value from a threadstorage +/// +/// @param name name of threadstorage +/// @param defValue [optional: default NaN] default value used when storage is created, create flag must be set +/// @param create [optional: default 0] when set the threadstorage is created if it did not exist or had an incompatible format, defValue must be given threadsafe Function TSDS_ReadVar(string name, [variable defValue, variable create]) + + variable argCheck = ParamIsDefault(defValue) + ParamIsDefault(create) + ASSERT_TS(argCheck == 2 || argCheck == 0, "defaul value and create must be either both set or both default.") ASSERT_TS(!IsEmpty(name), "name can not be empty") - if(ParamIsDefault(defValue)) - defValue = NaN - endif - - if(ParamIsDefault(create)) - create = 0 - else - create = !!create - endif + defValue = ParamIsDefault(defValue) ? NaN : defValue + create = ParamIsDefault(create) ? 0 : !!create WAVE/Z data = TSDS_Read(name) + if(WaveExists(data) && IsNumericWave(data) && DimSize(data, ROWS) == 1) + return data[0] + endif - if(!WaveExists(data)) - if(create) - TSDS_Write(name, var = defValue) - endif + ASSERT_TS(create == 1, "Error reading from threadstorage:" + name) - return defValue - endif + TSDS_Create(name, defValue) - return data[0] + return defValue End +/// @brief Reads a single wave ref wave from a named threadstorage threadsafe static Function/WAVE TSDS_Read(string name) - TUFXOP_GetStorage/Q/N=name/Z wv - if(V_flag) - return $"" + TUFXOP_GetStorage/Q/N=name/Z wv + if(!V_flag && WaveExists(wv) && IsWaveRefWave(wv) && DimSize(wv, ROWS) == 1) + return wv[0] endif - if(!WaveExists(wv) || !IsWaveRefWave(wv) || DimSize(wv, ROWS) != 1) - return $"" - endif + return $"" +End + +/// @brief Writes a numerical value to a threadstorage, if the threadstorage does not exist it is automatically created. +/// +/// @param name name of threadstorage +/// @param var numerical value that should be written +/// @returns 0 if write was successful, 1 if write was not successful +threadsafe Function TSDS_WriteVar(string name, variable var) + + ASSERT_TS(!IsEmpty(name), "name can not be empty") - WAVE/Z data = wv[0] + WAVE/Z data = TSDS_Read(name) + if(WaveExists(data) && IsNumericWave(data) && DimSize(data, ROWS) == 1) + data[0] = var - if(!WaveExists(data) || !IsNumericWave(data) || DimSize(wv, ROWS) != 1) - return $"" + return NaN endif - return data + TSDS_Create(name, var) End diff --git a/Packages/tests/Basic/UTF_Debugging.ipf b/Packages/tests/Basic/UTF_Debugging.ipf index a67ad5d7f9..eca9aa350f 100644 --- a/Packages/tests/Basic/UTF_Debugging.ipf +++ b/Packages/tests/Basic/UTF_Debugging.ipf @@ -26,9 +26,6 @@ Function BUG_TSWorks1() TUFXOP_Clear/N=(TSDS_BUGCOUNT)/Q/Z - bugCount = TSDS_ReadVar(TSDS_BUGCOUNT) - CHECK_EQUAL_VAR(bugCount, NaN) - BUG_TS("abcd") bugCount = TSDS_ReadVar(TSDS_BUGCOUNT) @@ -49,9 +46,6 @@ Function BUG_TSWorks2() TUFXOP_Clear/N=(TSDS_BUGCOUNT)/Q/Z - bugCount = TSDS_ReadVar(TSDS_BUGCOUNT) - CHECK_EQUAL_VAR(bugCount, NaN) - numThreads = 10 Make/FREE/N=(numThreads) junk = NaN diff --git a/Packages/tests/Basic/UTF_ThreadsafeDataSharing.ipf b/Packages/tests/Basic/UTF_ThreadsafeDataSharing.ipf index 1509ba21ee..d0ca4a298d 100644 --- a/Packages/tests/Basic/UTF_ThreadsafeDataSharing.ipf +++ b/Packages/tests/Basic/UTF_ThreadsafeDataSharing.ipf @@ -22,14 +22,7 @@ End static Function ChecksParams() try - TSDS_Write(KEY) - FAIL() - catch - PASS() - endtry - - try - TSDS_Write("", var = 1) + TSDS_WriteVar("", 1) FAIL() catch PASS() @@ -46,11 +39,11 @@ End static Function WriteWorks1() variable var - TSDS_Write(KEY, var = 123) + TSDS_WriteVar(KEY, 123) var = TSDS_ReadVar(KEY) CHECK_EQUAL_VAR(var, 123) - TSDS_Write(KEY, var = 567) + TSDS_WriteVar(KEY, 567) var = TSDS_ReadVar(KEY) CHECK_EQUAL_VAR(var, 567) End @@ -58,24 +51,27 @@ End static Function ReadWorks1() variable var - var = TSDS_ReadVar(KEY) - CHECK_EQUAL_VAR(var, NaN) + try + TSDS_ReadVar(KEY) + FAIL() + catch + PASS() + endtry - TSDS_Write(KEY, var = 123) + TSDS_WriteVar(KEY, 123) var = TSDS_ReadVar(KEY) CHECK_EQUAL_VAR(var, 123) End static Function ReadWorksWithDefault() - variable var - var = TSDS_ReadVar(KEY, defValue = 567) - CHECK_EQUAL_VAR(var, 567) - - // but it is still not created - var = TSDS_ReadVar(KEY) - CHECK_EQUAL_VAR(var, NaN) + try + TSDS_ReadVar(KEY, defValue = 567) + FAIL() + catch + PASS() + endtry End static Function ReadWorksWithDefaultAndCreate() @@ -92,8 +88,8 @@ End static Function ReadBrokenStorage1() variable var - var = TSDS_ReadVar(KEY, create = 1) - CHECK_EQUAL_VAR(var, NaN) + var = TSDS_ReadVar(KEY, defValue = 0, create = 1) + CHECK_EQUAL_VAR(var, 0) // top level has the wrong size TUFXOP_GetStorage/N=KEY wv @@ -101,15 +97,19 @@ static Function ReadBrokenStorage1() Redimension/N=0 wv - var = TSDS_ReadVar(KEY) - CHECK_EQUAL_VAR(var, NaN) + try + TSDS_ReadVar(KEY) + FAIL() + catch + PASS() + endtry End static Function ReadBrokenStorage2() variable var - var = TSDS_ReadVar(KEY, create = 1) - CHECK_EQUAL_VAR(var, NaN) + var = TSDS_ReadVar(KEY, defValue = 0, create = 1) + CHECK_EQUAL_VAR(var, 0) // contained wave is null TUFXOP_GetStorage/N=KEY wv @@ -117,6 +117,10 @@ static Function ReadBrokenStorage2() wv[0] = $"" - var = TSDS_ReadVar(KEY) - CHECK_EQUAL_VAR(var, NaN) + try + TSDS_ReadVar(KEY) + FAIL() + catch + PASS() + endtry End diff --git a/Packages/tests/UTF_HelperFunctions.ipf b/Packages/tests/UTF_HelperFunctions.ipf index 6eedcfbb97..a859bb6ada 100644 --- a/Packages/tests/UTF_HelperFunctions.ipf +++ b/Packages/tests/UTF_HelperFunctions.ipf @@ -165,7 +165,7 @@ Function AdditionalExperimentCleanup() KillVariables bugCount TUFXOP_AcquireLock/N=(TSDS_BUGCOUNT) - TSDS_Write(TSDS_BUGCOUNT, var = 0) + TSDS_WriteVar(TSDS_BUGCOUNT, 0) TUFXOP_ReleaseLock/N=(TSDS_BUGCOUNT) KillOrMoveToTrash(wv = GetOverrideResults()) @@ -858,7 +858,7 @@ Function CheckForBugMessages() endif TUFXOP_AcquireLock/N=(TSDS_BUGCOUNT) - bugCount_ts = TSDS_ReadVar(TSDS_BUGCOUNT, defValue = 0) + bugCount_ts = TSDS_ReadVar(TSDS_BUGCOUNT, defValue = 0, create = 1) TUFXOP_ReleaseLock/N=(TSDS_BUGCOUNT) if(IsFinite(bugCount_ts)) @@ -873,7 +873,7 @@ Function DisableBugChecks() NVAR bugCount = $GetBugCount() bugCount = NaN - TSDS_Write(TSDS_BUGCOUNT, var = NaN) + TSDS_WriteVar(TSDS_BUGCOUNT, NaN) End /// @brief Exhaust all memory so that only `amountOfFreeMemoryLeft` [GB] is left