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