Once features in multithreaded mode
Manipulating Once features in multithreaded mode
Eiffel introduced the powerful mechanism of once routines. A once routine has a body that will be executed only once, at the first call. Subsequent calls will have no further effect and, in the case of a function, will return the same result as the first. This provides a simple way of sharing objects in an object-oriented context.
For multithreaded applications, the appropriate semantics is that once routines must be called once per thread (rather than once per process). This is the semantics supported by EiffelThread.
Then the once feature is not initialized once per process but once per thread. Your once feature will be called again in any new thread execution.
Once per Process/Thread
By default, once features are once per thread. This means that when a once feature is called in a thread, the Eiffel run-time will check whether it has been already computed in this thread. If not, the once feature will be initialized and computed. This corresponds to the most commonly desired behavior for once features in multithreaded mode: most of the time, a once called in a thread is not likely to share its result with other threads.
This is only the default, however: you may at times need to use "once per process" versus "once per thread". Objects created "once per process" in multithreading mode can be shared among threads. You can use a once key to indicate the mode you wish to use.
Specifying once per thread or once per process
As mentioned above, in multithreaded mode, the default once
syntax will ensure "once per thread", as in this example:
object_per_thread: OBJECT
-- Once per thread.
once
create Result.make
end
You could obtain the same effect by explicitly coding the "THREAD" once key:
object_per_thread: OBJECT
-- Once per thread.
once ("THREAD")
create Result.make
end
To ensure that a once function is executed only once per process, you would use the "PROCESS" once key:
object_per_process: OBJECT
-- New 'object' (once per process)
-- that could be shared between threads
-- without reinitializing it.
once ("PROCESS")
create Result.make
end
The same concepts apply to once procedures.
Obsolete syntax
The syntax shown above is the current standard syntax. However in Eiffel code written for previous versions, you may run across once keys for multithreaded systems which are expressed in a different syntax. Specifically, the obsolete syntax used a feature's note
clause to specify a once key, as in the following example.
object_per_process: OBJECT
-- Obsolete syntax
-- New 'object' (once per process)
-- that could be shared between threads
-- without reinitializing it.
note
once_status: global
once
create Result.make
end
Using once per object in a multithreaded system
It is possible to use a once key to specify a once function that is executed once per object. However, in a multithreaded system, it is important to understand that no automatic synchronization of access occurs in this case. So the following caution is given.
Caution: You should understand that in a multithreaded system, you must synchronize access to the result of a function executed once per object in the same way that you would synchronize access to class attributes.