Patricia Shanahan wrote:
Gregg Wonderly wrote:
I'm thinking more and more that this runAfter business should really be a O(1) thing. If runAfter() is implemented to return true, can not that decision be made at the time of enqueue? It just looks like so much of this is spread around to so few actual users in the current API. As I look over the usages, there is some fuzzy logic involved in some cases where the sequence number is used for ordering. In a couple of other cases, there is a specific task that another task wants to run after.

I am generally concerned about sequence number ordering, not just at this level but in reading about Jini generally. The problem is what to do if message n has already been processed when message m, m<n, arrives.

In the end, it seems like the API should be
something more like

TaskManager.addAfter( Task myTask, Task dependedOnTask );

That does not cover all the current cases, and would require multiple modules to keep their own Task lists and do the scans themselves.

For example, with the current system we can deal with many-reader-single-writer rules. A write has to wait for any access to the same "address". A read has to wait for writes to the same "address". Reads do not have to wait for each other.



and, there would be something like

TaskManager.addWithSequencer( Task myTask, new Sequencer() {
    public void runAfter( List<Task> lst, int cnt ) {
        // search lst and return result
    }
});

So that simple checks can be made for "hasSequencer".  The first
case could just result in a call like

TaskManager.addWithSequencer( Task myTask, new Sequencer() {
    public void runAfter( List<Task> lst, int cnt ) {
        int idx = lst.indexOf( dependedOnTask );
        return idx >= 0 && idx < cnt;
    }
});

This would remove all of the abiguity and calling into the "return false" implementations. You could tell at the point of the add(), what sequencing was going to apply, no searching back into the implementation class.

The more I think about it the more I feel TaskManager represents a coincidental coupling between two logically distinct modules:

1. A sequencer whose business is determining whether a task is runnable.

2. A thread pool whose business is allocation of runnable tasks to threads.

Separating these functions might allow different types of sequencer, including a trivial one for cases in which there are no sequencing requirements. In some cases, tasks may be being allocated to the same TaskManager to share a thread pool even if they have no sequence relationship.

That said, some of the code I've read suggests that I can probably make the sequencing more efficient by putting it in a utility module than it would be if every using module implemented it separately.

Patricia

That's very similar to the lines I was thinking along earlier, I started sketched something out, I can send it to you, you might find some parts useful or interesting.

Reply via email to