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.