4D v16.3Preemptive 4D processes |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
4D v16.3
Preemptive 4D processes
Preemptive 4D processes
4D Developer Edition 64-bit for OS X (and for Windows, available starting with 4D v16 R2) offers a powerful feature allowing you to execute 4D code in preemptive processes. Thanks to this new feature, your 4D compiled applications will be able to take full advantage of multi-core computers so that their execution will be faster and they can support more connected users. When run in preemptive mode, a process is dedicated to a CPU. Process management is then delegated to the system, which can allocate each CPU separately on a multi-core machine. When run in cooperative mode (the only mode available in 4D until 4D v15 R5), all processes are managed by the parent application thread and share the same CPU, even on a multi-core machine. As a result, in preemptive mode, overall performance of the application is improved, especially on multi-core machines, since multiple processes (threads) can truly run simultaneously. However, actual gains depend on the operations being executed. In return, since each thread is independent from the others in preemptive mode, and not managed directly by the application, there are specific constraints applied to methods that you want to be compliant with preemptive use. Additionally, preemptive execution is only available in certain specific contexts. The use of preemptive mode is available in 4D 64-bit versions only. The following execution contexts are currently supported:
If the execution context supports preemptive mode and if the method is "thread-safe", a new 4D process launched using the New process or CALL WORKER commands, or the "Run method" menu item, will be executed in a preemptive thread. Otherwise, if you call New process or CALL WORKER from an execution context that is not supported (for example on a remote 4D machine), the process is always cooperative. Note: You can run a process in preemptive mode from a 4D remote by starting a stored procedure on the server with the language, for example using Execute on server. 4D code can only be run in a preemptive thread when certain specific conditions are met. Each part of the code being executed (commands, methods, variables, etc.) must be compliant with preemptive use. Elements that can be run in preemptive threads are called thread-safe and those that cannot be run in preemptive threads are called thread-unsafe. Note: Since a thread is handled independently starting from the parent process method, the entire call chain must not include any thread-unsafe code; otherwise, preemptive execution will not be possible. This point is discussed in the When is a process started preemptively? paragraph. The "thread safety" property of each element depends on the element itself:
Basically, code to be run in preemptive threads cannot call parts with external interactions, such as plug-in code or interprocess variables. Accessing data, however, is allowed since the 4D data server supports preemptive execution. By default, 4D executes all the project methods of your application in cooperative mode. If you want to benefit from the preemptive mode feature, the first step consists of explicitly declaring all methods that you want to be started in preemptive mode whenever possible -- that is, methods that you consider capable of being run in a preemptive process. The compiler will check that these methods are actually thread-safe (see Writing a thread-safe method for more information). You can also disallow preemptive mode for some methods, if necessary. Keep in mind that declaring a method "capable" of preemptive use makes it eligible for preemptive execution but does not guarantee that it will actually be executed in preemptive mode at runtime. Starting a process in preemptive mode results from an evaluation performed by 4D regarding the properties of all the methods in the call chain of the process (for more information, see When is a process started preemptively? below). To declare your method eligible for use in preemptive mode, you need to use the Execution mode declaration option in the Method Properties dialog box: The following options are provided:
Note: A component method declared as "Shared with components and host databases" must also be declared "capable" in order to be run in a preemptive thread by the host database. When exporting the method code using, for example, METHOD GET CODE, the "preemptive" property is exported in the "%attributes" comment with a value of "capable" or "incapable" (the property is not available if the option is "Indifferent"). The METHOD GET ATTRIBUTES and METHOD SET ATTRIBUTES commands also get or set the "preemptive" attribute with a value of "indifferent", "capable", or "incapable". The following table summarizes the effects of the preemptive mode declaration options:
Reminder: Preemptive execution is only available in compiled mode. In compiled mode, when starting a process created by either New process or CALL WORKER methods, 4D reads the preemptive property of the process method (also named parent method) and executes the process in preemptive or cooperative mode, depending on this property:
The actual thread-safe property depends on the call chain. If a method with the property declared as "capable" calls a thread-unsafe method at either of its sublevels, a compilation error will be returned: if a single method in the entire call chain is thread-unsafe, it will "contaminate" all other methods and preemptive execution will be rejected by the compiler. A preemptive thread can be created only when the entire chain is thread-safe and the process method has been declared "Can be run in preemptive process". For example, consider the following project methods: //MyDialog project method //MyComp project method //CallDial project method //CallComp project method Executing a method in preemptive mode will depend on its "execution" property and the call chain. The following table illustrates these various situations:
4D allows you to identify the execution mode of processes in compiled mode:
To be thread-safe, a method must respect the following rules:
Note: In the case of a "Shared by components and host databases" method, the "Can be run in preemptive processes" property must be selected. (*) Worker processes allow you to exchange data between any processes, including preemptive processes. For more information, please refer to the About workers. Methods with the "Can be run in preemptive processes" property will be checked by 4D during compilation. A compilation error is issued whenever the compiler finds something that prevents it from being thread-safe: The symbol file, if enabled, also contains the thread safety status for each method: Since they are "external" accesses, calls to user interface objects such as forms, as well as to the Debugger, are not allowed in preemptive threads. The only possible accesses to the user interface from a preemptive thread are:
A significant number of 4D commands are thread-safe. In the documentation, the icon in the command property area indicates that the command is thread-safe. You can get a list of thread-safe commands in the Language Reference manual. You can also use Command name which can return the thread safety property for each command. When a method uses a command that can call a trigger, the 4D compiler evaluates the thread safety of the trigger in order to check the thread safety of the method: SAVE RECORD([Table_1]) //trigger on Table_1, if it exists, must be thread-safe Here is the list of commands that are checked at compilation time for trigger thread safety:
If the table is passed dynamically, the compiler may sometimes not be able to find out which trigger it needs to evaluate. Here are some examples of such situations: DEFAULT TABLE([Table_1]) In this case, all triggers are evaluated. If a thread-unsafe command is detected in at least one trigger, the whole group is rejected and the method is declared thread-unsafe. Error-catching methods installed by the ON ERR CALL command must be thread-safe if they are likely to be called from a preemptive process. In order to handle this case, the compiler now checks the thread safety property of error-catching project methods passed to the ON ERR CALL command during compilation and returns appropriate errors if they do not comply with preemptive execution. Note that this checking is only possible when the method name is passed as a constant, and is not computed, as shown below: ON ERR CALL("myErrMethod1") //will be checked by the compiler In addition, starting with 4D v15 R5, if an error-catching project method cannot be called at runtime (following a thread safety issue, or for any reason like "method not found"), the new error -10532 "Cannot call error handling project method 'methodName'" is generated. A process can dereference a pointer to access the value of another process variable only if both processes are cooperative; otherwise, 4D will throw an error. In a preemptive process, if some 4D code tries to dereference a pointer to an interprocess variable, 4D will throw an error. Example with the following methods: Method1: myVar:=42 Method2: $value:=$1-> If either the process running Method1 or the process running Method2 is preemptive, then the expression "$value:=$1->" will throw an execution error. The use of DocRef type parameters (opened document reference, used or returned by Open document, Create document, Append document, CLOSE DOCUMENT, RECEIVE PACKET, SEND PACKET) is limited to the following contexts:
For more information about the DocRef reference, please refer to the DocRef: Document reference number section.
See also
|
PROPERTIES
Product: 4D
HISTORY
Created: 4D v15 R5 ARTICLE USAGE
4D Language Reference ( 4D v16.1) |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||