2
votes

How can I access a dynamic thread name in ColdFusion? Normally if I'm using a dynamic variable name, I'd do something like this:

<cfloop from="1" to="10" index="counter" > 
    <cfset Names[counter] = rereplace( createUUID(), "[-_\.]", "", "all") />
    <cfset something[ Names[counter] ] = 1 />
</cfloop>

<cfoutput>
    #( something[ Names[1] ] + something[ Names[2] ] + something[ Names[3] ]  )#
</cfoutput>

However, trying to do this with threads seems trickier, as I can't find a way to instantiate them besides using <cfthread>, which doesn't want to allow me to create a thread as a struct member. Here's what I've tried:

Attempt 1

<cfloop from="1" to="10" index="counter" > 
    <cfset ThreadNames[counter] = rereplace( createUUID(), "[-_\.]", "", "all") />
    <cfthread action="run" name="#something[ ThreadNames[counter] ]#" > 
        <cfset Thread.something = 1 />
    </cfthread>
</cfloop>

Element ... is undefined in a CFML structure referenced as part of an expression.

This one gets as far as the output before throwing an error. I didn't really expect the thread to be in the variables scope, but I can't specify the scope and I also can't find what scope it's built into. In short, I can't figure out how to access the thread from there:

Attempt 2

<cfloop from="1" to="10" index="counter" > 
    <cfset ThreadNames[counter] = rereplace( createUUID(), "[-_\.]", "", "all") />
    <cfthread action="run" name="#ThreadNames[counter]#" > 
        <cfset Thread.something = 1 />
    </cfthread>
</cfloop>

<cfthread action="join" name="#ThreadNames[1]#, #ThreadNames[2]#, #ThreadNames[3]#" />

<cfoutput>
    #( VARIABLES[ThreadNames[1]].something  + VARIABLES[ThreadNames[2]].something  + VARIABLES[ThreadNames[3]].something  )#
</cfoutput>

Element ... is undefined in a Java object of type class coldfusion.runtime.VariableScope.

Non-dynamic Example

For reference, here's how the code looks before trying to throw in the uuids

<cfloop from="1" to="10" index="counter" > 
    <cfthread action="run" name="thread#counter#" > 
        <cfset Thread.something = 1 />
    </cfthread>
</cfloop>

<cfthread action="join" name="thread1, thread2, thread3" />

<cfoutput>
    #( thread1.something  + thread2.something  + thread3.something  )#
</cfoutput>
1
You can’t access threads like that. You can join a thread after it completes, but you cannot simply write to a variable inside a running thread unless it is in a shared scope (like application or session), but you better be careful even doing that. - Redtopia
I'm not sure what you mean. Variables created inside of threads have their own scope that can be accessed after they're joined. - Patrick Schomburg
your example is just wrong. I’m not sure what you’re trying to do when you execute thread[name].variableName = 1; Maybe you could explain what you’re trying to accomplish. - Redtopia

1 Answers

3
votes

I have updated this answer in order to simplify my example. Previously, I had stored the thread name in an application variable key. This is unneccessary unless, you wish to store the values globally. The 'variables' scope is quite sufficient.

Important:

When you use the 'run' action, it is a 'set & forget' action. Any thread scoped variables created cannot be accessed externally, unless the thread is joined. An alternative approach is to create variables in a shared scope, like the 'application' or 'session' scope. Any changes made to a shared scope variable from within a thread can be accessed externally.

Implementation:

Access the thread name by passing it in, using the 'attributes' scope. By storing the thread name within the thread, you can ensure that the thread has executed and will exist, at the time the threads are joined.

<cfset variables.threadNames = {} />

<cfloop from="1" to="10" index="counter" > 
  <cfset variables.threadName = REReplace(CreateUUID(), "[-]", "", "all") />
  <cfthread action="run" name="#variables.threadName#" threadName="#variables.threadName#" counter="#counter#"> 
    <cfset thread.something = attributes.counter />
    <cfset variables.threadNames[attributes.threadName] = thread.something />
  </cfthread>
</cfloop>

<cfthread action="join" name="#StructKeyList(variables.threadNames)#" timeout="6000" />

<cfloop collection="#variables.threadNames#" item="key">
  <cfset variables.thread = cfthread[key]>
  <cfdump var="#variables.thread#" />
</cfloop>