Prompt function is not allowed in ThreadSafe function
viralvector
Apparently, I cannot use the function of prompt in ThreadSafe...
e.g.
ThreadSafe Function ThreadWorker(wIn, wln_control, waveIndex,xr,xl)
variable xr,xl
....
Prompt xl, "Enter left bracket:"
Prompt xr, "Enter right bracket:"
DoPrompt "Enter left and right", xl, xr
wave w1 = wln_control
duplicate/R=(xl, xr)/FREE w1, rw, bdw
duplicate/R=(xl, xr)/FREE wIn, tdw
rw = (bdw - tdw)^2 / numpnts(rw)
Variable MeanSquare = sum(rw)
....
Any workaround ideas?
Thanks in advance.
It doesn't really make sense to ask for user input from a thread- that's a technique to gain high performance. Waiting for a user to enter data is not high performance.
I presume that what you want is to thread a computation for speed, but that computation needs user input. Your prompts need to be in the driver function so that the inputs can be collected first, then passed into the thread worker functions, possibly via input parameters.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
June 5, 2014 at 04:32 pm - Permalink
Your presumption is right! but I don't know how to integrate the function into the driver function.
This is what I have tried, and I received:
"Expected operand"
Igor found an operator where it expected an operand.
This can also happen if you forget to use a comma after a numeric operand
Here is the code:
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
Menu "SME_PEAK"
"Multi-CPUs MSE & Peak", ThreadMSE_PEAK()
End
// These control various troubleshooting items and other aspects of the demonstration
Constant kNumDatasetsToProcess =10 // Number of sample input waves to create and process
Constant kSampleWaveNumPoints = 1000 // Number of points in each sample input wave
Constant kPrintStartThreadMessage = 1
Constant kPrintGotThreadDFMessage = 1
Constant kSimulateVaryingComputationTime = 1
ThreadSafe Function ThreadWorker(wIn, wln_control, waveIndex,xr,xl)
variable xr,xl
wave wIn
WAVE wln_control
Variable waveIndex
String NameWave = NameofWave(wIn)
Wavestats/q/z wIn
variable xPeak = V_maxloc
Variable i,n=numpnts(wIn), massTimesX=0
for(i=0; i<n; i+=1)
massTimesX += wIn[i]*pnt2x(wIn,i)
endfor
Variable totalMass=sum(wIn)
Variable centerOfMass= massTimesX/totalMass
//SP nile red living
//Variable xl=30
//Variable xr =50
//SP nile red living photodamage
//Variable xl=20
//Variable xr =55
//SP nile red
//Variable xl=30
//Variable xr =50
//SP nile red solvents
//Variable xl=5
//Variable xr =90
//C102 solvents
//Variable xl=400
//Variable xr =580
// Nile Blue 404
// Variable xl=550
// Variable xr =700
//NB 561
// Variable xl=600
// Variable xr =700
// Nile red
// Variable xl=530
// Variable xr =680
// Nile red solvents
// Variable xl=500
//Variable xr =700
// wave w2= wln
// Prompt xl, "Enter left bracket:"
//Prompt xr, "Enter right bracket:"
//DoPrompt "Enter left and right", xl, xr
wave w1 = wln_control
duplicate/R=(xl, xr)/FREE w1, rw, bdw
duplicate/R=(xl, xr)/FREE wIn, tdw
rw = (bdw - tdw)^2 / numpnts(rw)
Variable MeanSquare = sum(rw)
// print wIn
// This is used to simulate varying computation time
if (kSimulateVaryingComputationTime > 0)
Variable randomSecs = abs(enoise(kSimulateVaryingComputationTime))
Sleep/S randomSecs
endif
//Variable wMin = WaveMin(wIn)
//Variable wMax = WaveMax(wIn)
// Create data folder to return to calling thread
NewDataFolder/S output
// Create output variables
// Variable/G gMin = wMin
Variable/G gMeanSquare = MeanSquare//centerOfMass
Variable/G gxPeak = xPeak
String/G gNameWave=NameWave
// This tells the calling thread which wave was processed
Variable/G gWaveIndex = waveIndex
// Send data back to main thread
ThreadGroupPutDF 0, :
return 0 // Success
End
Function ThreadMSE_PEAK(xr,xl)
variable xl
variable xr
prompt xl,"enter xl"
Prompt xr,"enter xr"
Doprompt "Enter values", xl,xr
return xl&xr
if (IgorVersion() < 6.23)
Abort "This demo requires Igor Pro 6.23 or later."
endif
Variable t0 = StopMSTimer(-2) // Used to time the function
//if (V_flag)
// return -1
// endif
DFREF originalDFR = GetDataFolderDFR()
DFREF outputDFR = GetDataFolderDFR()
Variable numDatasetsToProcess = kNumDatasetsToProcess
Variable numDatasetsProcessed = 0
Variable numPointsInSampleData = kSampleWaveNumPoints
// Make output wave
Make/O/D/N=(numDatasetsToProcess,2) outputDFR:results = NaN
wave results= outputDFR:results
SetDimLabel 0,0,MeanSquareError,results
SetDimLabel 0,1,SP_Peak,results
make/O /T/N=(numDatasetsToProcess) outputDFR:resultstext
Wave/t resultstext = outputDFR:resultstext
DoWindow /F OutputTable
if (V_flag == 0)
Edit /N=OutputTable /W=(466,49,906,652) results.ld
Edit/N=OutputTableText resultstext
endif
// Look for sample data
// NewDataFolder /O :SampleData
//
DFREF inputDFR = :
// String name
// Variable i
// for(i=0; i<numDatasetsToProcess; i+=1)
// sprintf name, "(%d)", i // wave0, wave1
//Make/O/D/N=(numPointsInSampleData) inputDFR:$name = gnoise(1)
// SetDimLabel 0,i,$name,results
// endfor
// Create threads
Variable numThreads = ThreadProcessorCount
Variable threadGroupID = ThreadGroupCreate(numThreads)
SetDataFolder inputDFR // Needed for WaveRefIndexed
// Dispatch threads and collect output
Variable threadIndex
Variable waveIndex = 0
//control
wave wln_control = WaveRefIndexed("", 0, 1)
do
// Start any free threads
do
if (waveIndex >= numDatasetsToProcess)
break // No more input data to dispatch to a thread
endif
// Find a free thread
threadIndex = ThreadGroupWait(threadGroupID, -2) // Requires Igor Pro 6.23
threadIndex -= 1 // Because ThreadGroupWait returns threadIndex+1
if (threadIndex < 0)
break // No free threads
endif
// Start thread
Wave wIn = WaveRefIndexed("", waveIndex, 1)
// ThreadStart threadGroupID, threadIndex, ThreadWorker(wIn, wln_control, waveIndex,xl,xr)
ThreadStart threadGroupID, threadIndex, ThreadWorker(wIn, wln_control, waveIndex,xr,xl)
if (kPrintStartThreadMessage)
Printf "Started thread %d\r", threadIndex // For debugging only
endif
waveIndex += 1
while(1)
DFREF dfr = ThreadGroupGetDFR(threadGroupID, 0)
// create results as a 2 column matrix
//Make/O/D/N=(numDatasetsToProcess,2) outputDFR:results = NaN
// create gListInfo to store content in the same place that you create gCenterOfMass
// make sure it is initialized to be blank
// String/G gListInfo = ""
//
//if (DataFolderRefStatus(dfr) != 0)
//// Process results
// NVAR gcenterOfMass = dfr:gcenterOfMass
// NVAR gxPeak = dfr:gxPeak
// NVAR gWaveIndex = dfr:gWaveIndex
//SVAR gNameWave= dfr:gNameWave
//SVAR gNameWave= dfr:gListInfo
//// NVAR/DFREF=dfr gcenterOfMass, gxPeak, gWaveIndex
//// SVAR/DFREF=dfr gNameWave, gListInfo // create gListInfo when you create gNameWave
// results[gWaveIndex][0] = gcenterOfMass
// results[gWaveIndex][1] = gxPeak
//// gListInfo += num2str(gWaveIndex) + "=" + gNameWave + ";" // one option with num2str (use this or below, not both!)
// sprintf( "%s%d=%s;",gListInfo,gWaveIndex,gNameWave) // alternative with sprint (use this or above, not both!)
//
//
// See if thread output is available
if (DataFolderRefStatus(dfr) != 0)
// Process results
NVAR gMeanSquare = dfr:gMeanSquare
NVAR gxPeak = dfr:gxPeak
SVAR gNameWave= dfr:gNameWave
NVAR gWaveIndex = dfr:gWaveIndex
results[gWaveIndex][0] = gMeanSquare
results[gWaveIndex][1] = gxPeak
resultstext[gWaveIndex][0] =gNameWave
// Update the output table
DoUpdate
// For debugging only
if (kPrintGotThreadDFMessage)
Printf "%d %s : MeanSquare=%g, Peak=%g\r", gWaveIndex, gNameWave,gMeanSquare, gxPeak
endif
numDatasetsProcessed += 1
// This is a free data folder that would be killed automatically by Igor.
// Nonetheless we explicitly kill it here and now.
KillDataFolder dfr
endif
while(numDatasetsProcessed < numDatasetsToProcess)
Variable dummy = ThreadGroupRelease(threadGroupID)
Variable t1 = StopMSTimer(-2)
Variable elapsedTime = (t1 - t0) / 1E6
Printf "Finished ThreadMSE_PEAK in %.2f seconds.\r", elapsedTime
SetDataFolder originalDFR
End
June 6, 2014 at 11:46 am - Permalink
But keep your function, and move the Prompt/DoPrompt out if it into another function. Put all the UI code in that second function (that is, Prompt and DoPrompt) and have it call your engine function. Something like this:
"Multi-CPUs MSE & Peak", mThreadMSE_PEAK()
End
Function mThreadMSE_PEAK()
variable xl
variable xr
prompt xl,"enter xl"
Prompt xr,"enter xr"
Doprompt "Enter values", xl,xr
if (V_flag == 0)
ThreadMSE_PEAK(xr, xl)
endif
end
I like to start my menu-servicing functions with "m" to remind me what it's for. And it allows me to use the same function name as the engine that it calls.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
June 6, 2014 at 02:32 pm - Permalink
I like your way of managing macro functions with "m", and the code works flawlessly.
Thank you very much and have a nice weekend! johnweeks
June 6, 2014 at 06:17 pm - Permalink
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
June 9, 2014 at 09:36 am - Permalink