Lecture 28

10478 ワード

11 Other approaches


11.1 Atomic (Lock-Free) Data-Structure


This is not a general solution.
There is some internal locking going on behind the scene.

11.1.1 Compare and Assign Instrcution


CAA basically says the following:
  • I want the val to be changed from comp to nval
  • when CAA routine is trying to assign nval to val ,
  • if val is not comp , return false and fail the assignment
  • else, proceed and return true
  • int Lock = OPEN; // shared
    
    bool CAA(int & val, int comp, int nval){
      //begin atomic
      if(val == comp){
        val = nval;
        return true;
      }
      return false;
      //end atomic
    }
    
    void Task::main(){
      while(!CAA(Lock, OPEN, CLOSEd));
      // critical section
      Lock = OPEN;
    }

    11.1.2 Lock-Free Stack

    class Stack{
      Node *top;
     public:
      struct Node{
        //data
        Node * next;
      };
      
      void push(Node & n){
        for(;;){
          n.next = top;
         if(CAA(top, n.next, &n)) break;
        }
      };
      
      Node * pop(){
        Node * t;
        for(;;){
          t = top;
         if(t == nullptr) return t;
         if(CAA(top, t, t->next)) return t;
        }
      };
    }
    push() works, but pop() does not, at least not always.

    11.1.3 ABA problem


    Consider this to be the stack: top -> A -> B -> C pop() would not work if,
  • pop() called CAA(top, A, B) , and gets time sliced.
    so it wants to change top from A to B
  • Other task interrupts and calls 2 pops(), and pushes A back into the stack.A -> B -> C -> C -> A -> C
  • pop() routine comes back, and sees that top is still A , so it thinks nothing has been changed; the routine assignes top to be B which is popped off.top -> B -> ????
  • This cannot be fixed easily.

    11.1.4 Hardware Fix


    A solution for the problem above is to take advantage of double-wide CAVD instruction.
    This compares/assigns 64(or 128) bit values for 32(or 64) bit architectures.
    For CAV function itself, everything looks the same except the data types.
    But we will include some tickets attached to the node struct.
    bool CAVD(uintS_t & val, uintS_t comp, uintS_t nval){
      //begin atomic
      if(val == comp){
        val = nval;
        return true;
      }
      return false;
      //end atomic
    }
    
    class Stack{
      Node *top;
      union Link{
        struct{            // 32/64 bit data * 2
          Node *top;       // pointer to top node
          uintptr_t count; // ticket
        };
        uintS_t atom;      // raw form of above struct
      } link;
     public:
      struct Node{
        //data
        Link * next;
      };
      Stack() {link.atom = 0;}