|
|
Line 4: |
Line 4: |
| | | |
| I think we need to see some examples (well, I do for one). | | I think we need to see some examples (well, I do for one). |
− |
| |
− | == Examples ==
| |
− | The main thing to remember is that the proposal states that all features calls are asynchronous.
| |
− |
| |
− | Transactions are assured with transactional memory, probably implemented as software transactional memory.
| |
− | ----------------
| |
− | Example of transaction:<br/>
| |
− | feature<br/>
| |
− | correct_removal(container: DISPENSER) is<br/>
| |
− | transaction -- This is a transaction so it is assured to be atomic and isolated<br/>
| |
− | if<br/>
| |
− | not(container.is_empty)<br/>
| |
− | then<br/>
| |
− | container.remove<br/>
| |
− | end<br/>
| |
− | end<br/>
| |
− |
| |
− | This feature is assured to be correct because is is isolated and atomic with respect to the system. If the container has been modified between the call to is_empty and remove, the feature would be aborted and retried.
| |
− | -----------------
| |
− |
| |
− | feature<br/>
| |
− | incorrect_removal(container: DISPENSER) is<br/>
| |
− | do<br/>
| |
− | if<br/>
| |
− | not(container.is_empty)<br/>
| |
− | then<br/>
| |
− | container.remove<br/>
| |
− | end<br/>
| |
− | end<br/>
| |
− |
| |
− | This is the standard example of concurrency issues with preconditions. The container can change between the call to is_empty and remove. Using transactions avoids this.
| |
− | ----------------
| |
− |
| |
− | Example of concurrency:<br/>
| |
− | feature<br/>
| |
− | write_all_files is<br/>
| |
− | do<br/>
| |
− | write_file_1<br/>
| |
− | write_file_2<br/>
| |
− | write_file_3<br/>
| |
− | write_file_4<br/>
| |
− | end<br/>
| |
− |
| |
− | Since all feature calls would be asynchronous, the four write_file features could be executed in parallel if the runtime decides to do so. This is not a transaction so isolation across these calls is not assured.
| |
− | ----------------
| |
− |
| |
− | feature<br/>
| |
− | write_file is<br/>
| |
− | external<br/>
| |
− | "operating_system_write"<br/>
| |
− | abort<br/>
| |
− | "operating_system_abort"<br/>
| |
− | commit<br/>
| |
− | "operating_system_commit"<br/>
| |
− |
| |
− | This is how transactional features can be mapped on to external function calls that support transactional operations
| |
− | ----------------
| |
− |
| |
− | feature<br/>
| |
− | source: DISPENSER[ANY] --Where items are taken from<br/>
| |
− | destination: DISPENSER[ANY] -- where items are put after processing<br/>
| |
− | running: BOOLEAN -- Flag to stop processing<br/>
| |
− |
| |
− | consumer is<br/>
| |
− | do<br/>
| |
− | from<br/>
| |
− | until<br/>
| |
− | not (running)<br/>
| |
− | loop --This loop will spawn multiple threads, microthreads, hyperthreads, or whatever the implementation is and runtime chooses, all processing a single item.<br/>
| |
− | process_single_item<br/>
| |
− | end<br/>
| |
− | end<br/>
| |
− | <br/>
| |
− | process_single_item is<br/>
| |
− | local<br/>
| |
− | item: ANY<br/>
| |
− | transaction --Since this is a transaction, accessing the container is safe even when run concurrently.<br/>
| |
− | if<br/>
| |
− | not source.is_empty<br/>
| |
− | then<br/>
| |
− | item := source.item<br/>
| |
− | source.remove<br/>
| |
− | io.put_string(item.to_string)<br/>
| |
− | destination.put(item)<br/>
| |
− | end<br/>
| |
− | end<br/>
| |
− | <br/>
| |
− | ---------------
| |
− | Legacy externals example
| |
− |
| |
− | feature<br/>
| |
− | use_legacy_external(item: LEGACY_ITEM) is<br/>
| |
− | do<br/>
| |
− | print_item(item)<br/>
| |
− | log_item(item)<br/>
| |
− | --At this point the runtime will block until print_item and log_item have both committed, it will ensure nothing is running in the system and then run the external item serially. This is the non-concurrent way to ensure something executes as a transaction, isolated and atomic.<br/>
| |
− | use_item(item)<br/>
| |
− | end<br/>
| |
− | <br/>
| |
− | use_item(item: LEGACY_ITEM) is<br/>
| |
− | external<br/>
| |
− | "..."<br/>
| |
− | end<br/>
| |
− | <br/>
| |
− | print_item(item: LEGACY_ITEM) is<br/>
| |
− | do<br/>
| |
− | ...<br/>
| |
− | end<br/>
| |
− | <br/>
| |
− | log_item(item: LEGACY_ITEM) is<br/>
| |
− | do<br/>
| |
− | ...<br/>
| |
− | end<br/>
| |
Discussion of the feasibility and desirability of implementing transactional concurrency in Eiffel.
I think we need to see some examples (well, I do for one).