2

I'm reading boost::shared_ptr source code and found it using this function to increase shared_ptr's use count(reference count):

inline void atomic_increment( int * pw )
{
    //atomic_exchange_and_add( pw, 1 );

    __asm__
    (
        "lock\n\t"
        "incl %0":
        "=m"( *pw ): // output (%0)
        "m"( *pw ): // input (%1)
        "cc" // clobbers
    );
}

Why not simply use the operator++ to do this? Does this give better performance?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
amazingjxq
  • 4,487
  • 7
  • 33
  • 35

2 Answers2

9

The ++ operator reads it's operand's current value, adds 1 and writes the result back. This can be three interruptible (i.e., by another thread) steps. If two threads do this at the same time it is possible that the result is wrong. To protect against this one must use atomic operations or locks. This is done by the asm code shown above.

timos
  • 2,637
  • 18
  • 21
  • 1
    Now, in C++0x, they should use std::atomic and std::atomic_address instead of the assembly code. – Hrishi Jul 18 '12 at 01:30
  • 4
    In C++11, you should use std::shared_ptr instead of boost::shared_ptr – Chris Dodd Jul 18 '12 at 01:32
  • "_This can be three interruptible (i.e., by another thread) steps._" what do you mean by interruptible? Almost no CPU instruction is interruptible. Do you think that any compiler will not generate a single (non-interruptible) load, a single (non-interruptible) incr, a single (non-interruptible) store for `++`? – curiousguy Jul 19 '12 at 11:13
  • 1
    @curiousguy: Why do you think instructions such as load and store are uninterruptible? What I meant in my post was that it is possible that thread A loads the operand in a register, gets interrupted by thread B , thread B then performs the load, inc, store sequence, hence writing op+1 to memory, thread A regains control an performs inc, store, therefore also writing op+1. – timos Jul 19 '12 at 15:52
  • @timos "_Why do you think instructions such as load and store are uninterruptible?_" Do you know a single CPU where they are interruptible? "_it is possible that thread A loads the operand in a register, gets interrupted by thread B , thread B then performs the load, inc, store sequence, hence writing op+1 to memory, thread A regains control an performs inc, store, therefore also writing op+1._" So no instruction is interruptible, but the read-modify-write sequence of 3 instructions is interruptible and not atomic. Anyway, uninterruptible does not imply atomic. You are mixing concepts here. – curiousguy Jul 20 '12 at 07:13
  • An interruptible CPU instruction is an instruction which can takes very long, so the CPU may handle an interrupt during the execution of the instruction. The only example I know is the old loop instructions on x86. – curiousguy Jul 20 '12 at 07:18
  • @curiousguy That's not true, at least on any modern (i.e., Pentium) x86 CPU which employs pipelining any instruction can be interrupted, especially load/store instructions, they can take very long compared to arithmetic instructions. That's why caches have been introduced. If you want more information about such topics I recommend Hennessy/ Pattersons book on Computer Architecture. – timos Jul 20 '12 at 15:19
  • @timos Does this book say that (correctly aligned) load/store instructions are interruptible? – curiousguy Jul 20 '12 at 15:50
  • @curiousguy This has nothing to do with alignment. So yes. – timos Jul 20 '12 at 16:03
  • @timos "_This has nothing to do with alignment._" Hug? What is an interruptible instruction? – curiousguy Jul 20 '12 at 16:33
  • This discussion has very little to do with the original question, you should maybe open a new thread. – timos Jul 20 '12 at 16:37
3

The C++ standard does not guarantee the i++ or ++i operations to be atomic. So depending on compiler it may or may not be atomic. This workaround uses assembly language to get around this limitation. Now, the C++ standard includes std::atomic<T> that guarantees the operations on the object to be atomic.

Hrishi
  • 699
  • 1
  • 4
  • 13