On Mon, Aug 25, 2003 at 10:54:46AM +0900, Philip Mak wrote:
> So that means @@num_sending must have become -1 somehow, in order for
> a ZeroDivisionError to occur.
>
> But @@num_sending is initialized to 0, and this is the only place in
> the code where it is modified:
>
> begin
> @@num_sending += 1
> yield limit
> ensure
> @@num_sending -= 1
> end
>
> So how could @@num_sending have become -1? It can only be decremented
> after being incremented. Could the fact that this class is used by
> multiple threads simultaneously have something to do with it? But I
> still don't see how it could happen...
As you point out, your code is not threads-safe

Consider the following scenario:
* 2 threads, called A and B
* thread A is the first to enter that section of code. In order to do
@@num_sending += 1, it first grabs @@num_sending (which is 0) and
then adds 1 (ie. it's not an atomic operation). Imagine that just
after A takes the value of @@num_sending, B does the same. You'll
then have the following

A B
take @@num_sending => 0
take @@num_sending => 0
add 1
store 1 in @@num_sending
(@@num_sending = 1 here) add 1
store 1 in @@num_sending
(@@num_sending = 1 here)

Now, the -= 1 operations could happen "atomically" (no thread
switching in the middle), then

take value => 1
substract 1
store (0)
take value => 0
substract 1
store -1

The solution is changing your code or using a mutex.

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

I did this 'cause Linux gives me a woody. It doesn't generate revenue.
-- Dave '-ddt->` Taylor, announcing DOOM for Linux