| **Navigation:**  [[advanced topics 1.htm|Advanced Topics]] > Thread Model Documentation > Multi-Threading Programming >====== Thread Synchronization ====== | [[mtcoding techniques for preemptive multi threading.htm|{{btn_prev_n.gif|Previous page}}]][[advanced topics 1.htm|{{btn_home_n.gif|Return to chapter overview}}]][[mtsynchronization objects.htm|{{btn_next_n.gif|Next page}}]] | | || The Clarion runtime has a variety of built in interfaces and procedures to help you maintain synchronization between your threads. The POST and EVENT functions have always been in the Clarion language for thread synchronization. SUSPEND and RESUME functions allow you to stop and start another thread, INSTANCE allows you to get another thread's contents for a variable and the ICriticalSection, IMutex, ISemaphore and IReaderWriterLock are interfaces to objects that allow you to synchronize the processing between multiple threads and also multiple processes. **POST/EVENT** You have always been able to synchronize thread processing by posting an event from one thread to another using [[post post user defined event .htm|POST()]] to send the event and [[event return event number .htm|EVENT()]] to receive it. See the SUSPEND/RESUME section below for an example on using these functions to synchronize two threads. **SUSPEND/RESUME** [[suspend suspend thread execution.htm|SUSPEND]] allows you to stop another process. [[resume resume thread execution .htm|RESUME]] starts that process again. You can issue multiple SUSPEND calls for a thread. The same number of RESUME calls must be made for that thread to restart. The SUSPEND procedure suspends a thread specified by the //threadno// parameter. If the //threadno// parameter is a number of an active thread, its execution is suspended and a suspending counter is incremented. Each additional SUSPEND statement issued to the same active thread will increment the suspending counter by one. Therefore, a thread that has been suspended with a given number of SUSPEND statements can only resume thread execution when an equal number of RESUME statements has been executed. //EXTREME CAUTION// should be taken with MDI programs using SUSPEND, as improper use can cause program lockups. All MDI child windows have an MDI client window as a parent, and the MDI client window can send rather than post messages to its child windows. For example, calling the inter-thread SendMessage modal function causes the calling thread (the MDI client window) to suspend activity until the called thread (the MDI Child window) returns from the call. If the called thread is suspended, we would have a program lockup. The SUSPEND and RESUME functions can be very useful for controlling threads that are CPU intensive. For example, rebuilding keys on a file. Here is an example program that starts a BUILD of a file and allows the user to pause the build and restart it. PROGRAM MAP DoBuild(STRING) END MyFile FILE,DRIVER('TopSpeed'),PRE(F) Key1     KEY(F:Field1),PRIMARY Key2     KEY(F:Field2) Key3     KEY(F:Field3, Field4) RECORD Field1     LONG Field2     STRING(20) Field3     STRING(20) Field4     STRING(20) END END BuilderWin WINDOW('Building File'),AT(,,81,22),GRAY BUTTON('Suspend Build'),AT(2,3,75,14),USE(?Button) END AllDone  EQUATE(500H) Building BYTE ThreadID SIGNED,AUTO CODE OPEN(BuilderWin) ThreadID = START(DoBuild, , THREAD()) Building = TRUE ACCEPT CASE EVENT() OF AllDone MESSAGE('Build Complete') BREAK OF Event:Accepted IF ACCEPTED() = ?Button IF Building SUSPEND(ThreadID) ?Button{PROP:Text} = 'Resume Building' ELSE RESUME(ThreadID) ?Button{PROP:Text} = 'Suspend Build' END END END END DoBuild PROCEDURE (parent) CODE MyFile{PROP:FullBuild} = TRUE BUILD(MyFile) POST(AllDone,,parent) **INSTANCE** In versions of Clarion prior to Clarion 6.0 a variable's memory location was constant regardless of which thread accessed the variable. Therefore this code would always work: PROGRAM MAP AFunc() END GlobVar SIGNED,THREAD Addr    LONG CODE Addr = ADDRESS(GlobVar,1) START(AFunc) AFunc PROCEDURE CODE IF Addr <;> ADDRESS(GlobVar) MESSAGE('Panic') END This sort of code was used in ABFILE.CLW to make sure the file manager matched the file it was meant to manage. To allow programs to know what variable they are really using you can now use the [[instance return variable s thread instance address 1.htm|INSTANCE]] function to get the address of the variable on any thread, and most importantly on thread 1. The above code would need to be modified as follows to work in Clarion 6.0. PROGRAM MAP AFunc() END GlobVar SIGNED,THREAD Addr    LONG CODE Addr = ADDRESS(GlobVar) START(AFunc) AFunc PROCEDURE CODE IF Addr <;> INSTANCE(GlobVar,0) MESSAGE('Panic') END