The interpreter also has a "last executed" variable, which contains the serial number of the latest command to finish executing. |
those parameters are zero, the operation would proceed. If a non-zero value is found, the interpreter would sleep and retry that field later. |
those parameters are equal or less than "last executed", the interp knows that the parameters are up to date, and the operation would proceed. If not, the interpreter would sleep and retry that field later. |
would look at each parameter on its "params to write" list. If the "latest writer" number matches the operation's serial number, it updates the parameter, then sets "latest writer" to zero, to indicate that the parameter is up to date. If the "latest writer" field is non-zero but doesn't match the serial number of the current operation, it updates the parameter but doesn't touch "latest writer". Some subsequent queued operation will also be writing to that parameter, and it shouldn't be marked as current until that operation finishes. (If an intermediate operation needed the result of the current operation, the interpreter would have stopped at that point and "latest writer" would contain the serial number of the current operation.) A complication occurs if the user aborts the program. If queued commands are discarded, the parameters that those params would have written to will still have non-zero "latest writer" values, which will not get cleared. Any subsequent command that needs to read one of those parameters would hang. A possible solution would be to keep a "last completed" serial number in the interpreter. Whenever a command finishes, it would update "last completed". Commands would still write their own serial numbers into the "latest writer" field of parameters that they intend to write when they start, but they would NOT examine or zero the field when they finish. The test for allowing an operation to be executed or queued would be 'all params to read have "latest writer" fields less than or equal to "last completed" ', instead of 'all params to read have "latest writer" fields set to zero'. With this arrangement, the only thing needed when aborting or flushing the queue is to set "last completed" to the current serial number, then increment the current number. The second arrangement is better in a number of ways - the command finishing code (which is probably realtime) doesn't need access to the "latest writer" fields of the entire parameter list, it only needs to be able to set "last completed". |
would update the interpreter's "last executed" variable. This is where I get a little fuzzy. Suppose operation 10 is queued, and operations 11 thru 20 are not (simple math expressions). If 11 thru 18 do not depend on anything that is written by 10, they can (and should) execute _before_ 10 finishes. If 19 does depend on something that 10 writes, it will have to wait until 10 completes. In particular, it will wait until "last executed" is greater or equal to 10. But if we allow 11 thru 18 to update "last executed" before 10 finishes, we have a problem. I know this can be solved, I just don't have a nice O(1) solution at the moment. |