Is incr/decr atomic in multithread mode?
Steve Chu
stvchu at gmail.com
Mon Feb 25 09:53:11 UTC 2008
On Mon, Feb 25, 2008 at 4:28 PM, dormando <dormando at rydia.net> wrote:
> Steve Chu wrote:
> > On Mon, Feb 25, 2008 at 2:51 PM, dormando <dormando at rydia.net> wrote:
> >> I think this is fine?
> >>
> >> Since the operations are independently atomic, it's perfectly valid for
> >> two threads to incr the same value.
> >>
> >
> > But for client api, they seems NOT atomic, because when Thread A just
> > has 'item_get' done but before 'add_delta', Thread B can still do
> > item_get.
> >
> > X-> set "foo" 1
> > A-> item_get "foo"
> > B-> item_get "foo"
> > A-> add_delta "foo" by 1
> > B-> add_delta "foo" by 1
> >
> > then A and B both hold value 2, which one should be stored?
> >
> > And the exact value we need is 3, right? I am not quit sure, correct
> > me if i am wrong:)
>
> The result gets copied into the thread-local 'temp' buffer, then copied
> into that connection (implicitly atomic)'s output buffer.
>
> So actually I read the code wrong the first time. This _should_ do the
> right thing:
>
> We have threads (A, B, X):
>
> X -> set 'foo' 1
>
> A -> process_arithmetic_command()
> note thread local storage (char temp[])
> B -> same.
>
> A -> it = item_get(key, nkey)
> (atomically increments the refcount for that item, returns a reference
> to it)
> B -> same, same time.
> (same)
>
> A -> out_string(c, add_delta(it, incr, delta, temp));
> add_delta runs atomically, copies the result of the addition into the
> thread local 'temp' buffer and _returns the 'temp' buffer_ (which
> contains 2)
> B -> out_string(c, add_delta(it, incr, delta, temp));
> Gets serialized behind A, and its 'temp' then holds a value one higher
> than A's (containing 3)
Here I am confused. Every thread has a local var 'temp' and here
'temp' should hold 2. 'temp' is independent, and doesn't share
between threads. So thread B should overwrite the value in the
slabber. Am I right?
> A -> runs out_string(c, temp), with 'temp' having the atomically
> incremented value.
> A -> inside out_string, copy's the contents of the original 'temp'
> buffer into the connection's local write buffer, then sets the
> connection into write mode (which will flush its buffer before doing
> further processing). Then returns.
> A -> returns to the state machine, 'temp' goes to the wolves, etc.
> A -> sends value '2' to its client.
>
> B -> Same thing. Client should receive a '3'.
>
> Apologies to the original patch author and the list for the confusion :)
> I had mentally confused "normal" responses and "get" responses, which
> operate differently.
>
> -Dormando
>
>
>
> >> It's possible that with two threads (A, B):
> >>
> >> X -> set "foo" 1
> >> A -> incr "foo" by 1
> >> B -> incr "foo" by 1
> >>
> >> A -> returns 3
> >> B -> returns 3
> >>
> >> The only guarantee the slabber makes for returning values, is that they
> >> won't get deleted before being transferred through the network.
> >>
> >> Could be wrong, but that's my impression from checking the sources.
> >>
> >> -Dormando
> >>
> >>
> >>
> >> Steve Chu wrote:
> >> > In 'process_arithmetic_command' function:
> >> > We first do item_get from slabs and then do add_delta to incr/decr the value.
> >> >
> >> > My question is:
> >> > Is this atomic in multithread mode? Item_get is atomic and so is
> >> > add_delta because they are protected by mutex. But the entire two
> >> > operations seems NOT atomic. Two threads can both do item_get with
> >> > same key, then both incr it, and write back.
> >> >
> >> > Anybody can tell me whether it is a bug or not?
> >> >
> >> > Regards,
> >> >
> >> > Steve Chu
> >>
> >>
> >
>
>
--
Steve Chu
http://stvchu.org
More information about the memcached
mailing list