Previous: Inheritance Up: Atomicity Next: Examples

Pitfalls

The following issues should be kept in mind when using atomic functions.

  1. Atomic functions should be used sparingly. This is because of the high performance cost associated with the decrease in parallelism they represent. Many applications will have no need for atomic functions.

  2. When it is necessary to use an atomic function, encapsulate only what is absolutely necessary within the atomic function. These functions should be small and simple.

  3. Because atomic functions provide a means to manipulate shared mutable variables, it is easy to fall into the trap of a busy wait similar to the fair interleaving pitfall described in Section . For example, consider:
    
    class Trouble {
      private: 
        int x; 
      public:
        atomic void assign (int i) 
          { x = i; } 
        atomic int check (void) 
          { return x; } 
    };
    

    int main() { Trouble t; t.assign(0); par { t.assign(1); while (t.check()!=1) {} } ... }

    Though the language guarantees that eventually operations from both threads of control in the parallel block will get a chance to execute, there is no guarantee about how soon an operation from a particular thread (say the first one, which assigns 1 to t.x) will be chosen. Thus, we cannot be guaranteed to observe the termination of this parallel block.

  4. Because atomic functions are associated with an object, static members cannot be declared atomic. Similarly, functions at global scope (i.e. non-member functions) cannot be declared atomic.

  5. The actions within an atomic function can be interleaved with actions from nonatomic members of the same object. Thus, it is important to protect not only the write operations on mutable variables inside atomic functions, but also the read operations. The following class, for example, permits dangerous sharing.
    
    class Protect {
      private: 
        int x;
      public: 
        atomic void write (int i) { x = i; } 
        int read (void)           { return x; } 
    };
    

    To rectify the problem, the member function read() should be declared atomic as well. (Of course, there is no problem if the class is used in a manner that guarantees that no instance of write() is composed in parallel with any instances of read().)

paolo@cs.caltech.edu