CriticalObject

Built-in function to enwrap an object for multi-thread use. Such objects can be used from multiple threads without causing a crash.


OutputVar := CriticalObject(Object, lpCriticalSection)
Function Example: obj := CriticalObject(MyCriticalObject)

Parameters

OutputVar

The name of the variable in which to store the created object.

Object (optional)

Existing Object or CriticalObject to use, this can be also a pointer.
When CriticalObject is given, its CriticalSection will be used and second parameter will be ignored.
When this parameter is empty new object will be created and used.

lpCriticalSection (optional)

Pointer to a CriticalSection to use. When this parameter is omitted new CriticalSection will be created unless CriticalObject was given in first parameter, then its CriticalSection will be used.

General Remarks

How does it work:

To retrieve the pointer to original object from CriticalObject use:

object := CriticalObject(CriticalObject,1)

To retrieve the pointer to CriticalSection use:

lpCriticalSection := CriticalObject(CriticalObject,2)

When last reference to internal object is deleted, CrticalSection is deleted as well.

Operations like obj.key++ obj.key--, obj.key += 1, obj.key /= 2 and others access the object 2 times, once to get the value and another time to set the value.
Those operations will not produce desired result in multi-threaded environment when 2 or more threads change the value of an item.
To work around that we will need to lock/unlock the CriticalSection manually:

obj:=CriticalObject({a:0}) ; Create new CriticalObject
script:="
(
  obj:=CriticalObject(a_args[1]) ; get CriticalObject from pointer
  lpCS:=CriticalObject(obj,2) ; get CriticalSection
  loop 1000000
    EnterCriticalSection(lpCS),obj.a++,LeaveCriticalSection(lpCS) ; manually lock and unlock CriticalSection
)"

threads:=[]
loop 4
  threads.Push(TlsThread(script,ObjPtr(obj) "")) ; create 4 threads passing the pointer (as string!) to command line parameters
While threads[1].AhkReady() || threads[2].AhkReady() || threads[3].AhkReady() || threads[4].AhkReady() ; wait for threads to finish
  ToolTip obj.a
MsgBox obj.a ; = 4000000

Examples

obj := CriticalObject() ; Create new critical object
Threads:=[]
Loop 4 ; Create 4 Threads.
 threads.Push(NewThread("obj:=CriticalObject(" ObjPtr(obj) ")`nLoop`nobj[" A_Index "]:= A_Index"))
 
Loop ; Show current content of object.
 ToolTip obj.1 "`n" obj.2 "`n" obj.3 "`n" obj.4
Esc::ExitApp