On Mon, 16 Jun 2008 23:40:56 -0700, AliRezaGoogle <as*******@yahoo.com>
wrote:
Regarding to the code below my question is that why we have in out
put something like this: [...]
You have that output because the first thread can accomplish more than one
iteration before Windows steps in and tells it that its current turn with
the CPU is up.
There's nothing fundamentally wrong with how the code you posted is
behaving. It's doing exactly what one would expect, given the relative
simplicity of the loop and the speed of a modern computer. Windows grants
CPU time to a particular thread in something like 50 millisecond blocks,
and it takes a lot less than 50 ms for the code you posted to get through
one iteration.
So, each thread gets to complete multiple iterations in a row, before the
other thread then gets its turn with the CPU.
Monitor.Wait() changes the behavior because it specifically waits (hence
the name). The "wait" causes the thread to yield the CPU, and thus the
other thread gets a chance to run. And in particular, the Monitor class
maintains a queue of threads waiting on the lock, and the thread that
called Wait() won't get the lock until every other thread that was already
in the queue before it gets a chance at the lock.
Other ways to change the behavior of your code would include simply
calling Thread.Sleep(1) (yields the CPU without specifically reentering
the queue for the lock), adding a spin-wait outside the section protected
by Monitor.Enter/Exit() (would cause the thread to use up its 50 ms
quantum without reaquiring the lock), and running the code on a computer
with more than one CPU (would allow the other thread to acquire the lock
as soon as the first thread released it, even if the first thread still
has CPU time left in its quantum).
Finally, some random thoughts on the code you posted:
-- There's no point in calling Thread.Sleep() from your main thread
after you create the Thread objects. You haven't started the threads, so
sleeping does absolutely nothing. Even if you had started the threads,
sleeping is pointless. The threads would still get to run eventually, and
not much later than you started them. And you could control your main
thread's coordination with the other threads in a much more precise,
useful way simply by calling Join() on each thread instance after you
start them.
-- There's no point in having two practically identical methods. Just
pass use the current thread's own ID, or pass some unique identifier to
the thread procedure, where there's just a single thread procedure used by
both threads.
-- If you do go back and modify the code for any reason, you might as
well fix it so that the word "winner" is spelled correctly. Maybe even
change the code so that the word is _used_ correctly too. :)
Pete