| **Navigation:**  [[advanced topics 1.htm|Advanced Topics]] > Thread Model Documentation > Multi-Threading Programming >====== Threading Code Design Standards ====== | [[mtoverview.htm|{{btn_prev_n.gif|Previous page}}]][[advanced topics 1.htm|{{btn_home_n.gif|Return to chapter overview}}]][[mtcoding techniques for preemptive multi threading.htm|{{btn_next_n.gif|Next page}}]] | | || {{newc7.jpg|NewC7.jpg}} To allow Clarion to support preemptive threads some changes were required in the language. This was kept to a minimum so as to ease the migration of versions prior to Clarion 6 to our latest version. **THREAD attribute on Classes** Prior to Clarion 5.5 if you had a global variable that was an instance of a class the [[thread set thread specific memory allocation .htm|THREAD]] attribute was ignored. In Clarion 6 and higher any global instance of a class with the THREAD attribute will have separate data for each running thread. The constructor of the class will be called on thread initialization and the destructor will be called on thread termination. Thread "initialization" and thread "termination" must be defined because it is not always obvious. In general, any DLL has some entry point called by the OS on attaching that DLL to the process, detaching it from the process, on the start and closing a thread. The Clarion RTL translates every such call, to chains of calls to initialize or cleanup data in all modules that have application-wide or thread-wide variables declared. But in certain situations the OS does not do calls to executables, for example, if it is an EXE rather than DLL, or if the DLL is loaded dynamically by the call to LoadLibrary. In the latter case, the OS calls that DLL's entry point for initializing application-wide data only. The CW RTL handles all special cases and calls the code to initialize and also to cleanup threaded data. The order that class constructors are called is undefined. So do not assume that a different class instance has been constructed when your constructor is called This feature gives you a lot of power to control things on a thread-by-thread basis. The ABC templates use this strategy to make sure the meta-information about your database is available on each thread. See the section below "Using hand code" for an example of a global threaded class. **THREAD and **__EXTERNAL__**EXTERNAL__set_defined_externally_** In versions of Clarion prior to version 6, a variable with the THREAD attribute was allocated a fixed memory location and the runtime library handled swapping the thread specific values of that variable in and out of that memory location. So if you had a file definition in a DLL you would declare it as AFile FILE,DRIVER('TopSpeed'),THREAD Then in your EXE you would declare the file as AFile FILE,DRIVER('TopSpeed'),EXTERNAL A variable with the THREAD attribute has different memory allocated for each thread. The compiler generates code to make sure that the right memory is accessed regardless of which thread is running. For the compiler to generate the right code it needs to know if a variable has the THREAD attribute regardless of where the variable is defined. So in Clarion if you have a file definition in a DLL you declare it as AFile FILE,DRIVER('TopSpeed'),THREAD Then in your EXE you declare the file as AFile FILE,DRIVER('TopSpeed'),EXTERNAL, THREAD Notice the THREAD attribute is present in both declarations, unlike previous versions. **ADDRESS of a threaded variable** In version prior to Clarion 6, taking the [[address return memory address .htm|ADDRESS()]] of a threaded variable would always return the same result regardless of what thread is running. Every thread has its own memory location for a threaded variable. So ADDRESS() no longer will return the same value. If you need a constant address for a threaded global variable you can use the new function [[instance return variable s thread instance address 1.htm|INSTANCE()]] and pass a Thread Number of 0. For example, to get a unique identifier for a threaded FILE that you can be certain will be the same regardless of what thread you are on you used to do ADDRESS(MyFile). You now do INSTANCE(MyFile, 0) **LOCKTHREAD, UNLOCKTHREAD and THREADLOCKED** Clarion works with preemptive threads rather than cooperative threads these functions do nothing by default. However, if you want to work in a [[cooperative threading in a preemptive environment.htm|cooperative threading environment]] [[lockthread re lock the current execution thread .htm|LOCKTHREAD]] will call the SYSTEM{PROP:LockThreadHook} function, [[unlockthread unlock the current execution thread .htm|UNLOCKTHREAD]] will call the SYSTEM{PROP:UnlockThreadHook} function and [[threadlocked returns current execution thread locked state .htm|THREADLOCKED]] will call the SYSTEM{PROP:ThreadLockedHook} function. **See Also:** [[file declare a data file structure .htm|FILE]] [[external set defined externally .htm|EXTERNAL]] [[thread set thread specific memory allocation .htm|THREAD]] [[class object declaration .htm|CLASS]] [[address return memory address .htm|ADDRESS]]