D
David Levine
Jon,
I've taken a look at it and these comments are based on a code-inspection
but I did not verify the correctness if its operation by using it in a
sample.
The ctor for CustomThreadPool increments instanceCount before the
lock(staticLock)...why not inside of the lock?
The MinThreads and MaxThread properties do not validate the values...I
thought you were going to add some logic to detect and handle this.
The routines OnBeforeWorkItem and OnAfterWorkItem do not have a try-catch
that surrounds the callback. In addition, these routines are invoked from
method ExecuteWorkItem. This uses a try-catch around job.Invoke, but these
two routines are unprotected by a try-catch (there is a try-finally). The
routine ExecuteWorkItem is also not surrounded with a try-catch; this means
that if either throws an exception it will not be logged or otherwise
detected by logic in the Threadpool. I don't think the threadpool will be
in an indeterminate state, but at a minimum the cause of the unexpected
thread termination will not be recorded.
WorkerThreadLoop is much more readable; good job of refactoring.
The OnException method - I like to at least generate some trace output.
Exceptions should always be treated as abnormal occurrences, and some kind
of breadcrumbs should be left behind. As the note says, it could even log it
to the event log....I think that's an excellent idea. You could add
something at the end of the method so that if no callback handles it a
default action is taken.
Question about Monitor: In AddWorkItem the first action taken if the
queueCount is zero is to pulse the queueLock before adding the workItem to
the queue; why not pulse it after adding it to the queue? Also, in the path
where queueCount is greater then zero it never pulses the queue at all - why
is this not needed? (I think it's not needed but I want to check.) I notice
that you implement the worker priority here and start the thread if needed
after the item is added to the queue - looks good. As you noted, a binary
search may be useful here (low on the priority list).
I did not actually setup a sample and run it through its paces. A test
fixture/integration/unit test would be useful to validate it. Testing a
multi-threaded class is tricky but unit testing would at least verify the
non-timing related logic. If nothing else, others might find such a test jig
useful - could even turn into a little product.
On the whole it looks good.
Dave
PS: Have you had a chance to look at the exception document I sent?
I've taken a look at it and these comments are based on a code-inspection
but I did not verify the correctness if its operation by using it in a
sample.
The ctor for CustomThreadPool increments instanceCount before the
lock(staticLock)...why not inside of the lock?
The MinThreads and MaxThread properties do not validate the values...I
thought you were going to add some logic to detect and handle this.
The routines OnBeforeWorkItem and OnAfterWorkItem do not have a try-catch
that surrounds the callback. In addition, these routines are invoked from
method ExecuteWorkItem. This uses a try-catch around job.Invoke, but these
two routines are unprotected by a try-catch (there is a try-finally). The
routine ExecuteWorkItem is also not surrounded with a try-catch; this means
that if either throws an exception it will not be logged or otherwise
detected by logic in the Threadpool. I don't think the threadpool will be
in an indeterminate state, but at a minimum the cause of the unexpected
thread termination will not be recorded.
WorkerThreadLoop is much more readable; good job of refactoring.
The OnException method - I like to at least generate some trace output.
Exceptions should always be treated as abnormal occurrences, and some kind
of breadcrumbs should be left behind. As the note says, it could even log it
to the event log....I think that's an excellent idea. You could add
something at the end of the method so that if no callback handles it a
default action is taken.
Question about Monitor: In AddWorkItem the first action taken if the
queueCount is zero is to pulse the queueLock before adding the workItem to
the queue; why not pulse it after adding it to the queue? Also, in the path
where queueCount is greater then zero it never pulses the queue at all - why
is this not needed? (I think it's not needed but I want to check.) I notice
that you implement the worker priority here and start the thread if needed
after the item is added to the queue - looks good. As you noted, a binary
search may be useful here (low on the priority list).
I did not actually setup a sample and run it through its paces. A test
fixture/integration/unit test would be useful to validate it. Testing a
multi-threaded class is tricky but unit testing would at least verify the
non-timing related logic. If nothing else, others might find such a test jig
useful - could even turn into a little product.
On the whole it looks good.
Dave
PS: Have you had a chance to look at the exception document I sent?