Cond in sync of Go concurrency

package main

import (
   "fmt"
   "sync"
   "time"
)
/**
 * Cond as a coroutine
 */
func main() {
   var lc = new(sync.Mutex)
   //Why does this locker pass in a reference?
   var cond = sync.NewCond(lc)


   for i := 0; i < 5; i++ {
      go func(x int) {
         cond.L.Lock()
         defer cond.L.Unlock()
         cond.Wait()
         fmt.Printf("value is %d\n",x)
      }(i)
   }
   //Sleep for a while, make sure that one of the following Signal() can be notified (could it not be notified?)
   time.Sleep(2*time.Second)

   for i:=0;i<3;i++{
      fmt.Printf("Wake up the %d goroutine\n", i)
      cond.Signal()
      time.Sleep(time.Second*1)
   }
   fmt.Println("all wake up")
   cond.Broadcast()
   time.Sleep(2*time.Second)
}

//-----------------------turn out----------------------- -

Wake up the 0th GO process
value is 1
wake up the 1st GO process
value is 0
wake up the 2nd GO process
value is 3
wake up all
value is 2
value is 4

 

 

In the go process, Cond acquires the lock separately and is in a waiting state. Why he can acquire a memory lock in the go process depends on the memory design of the go language.

Call Wait() to acquire the lock separately and enter the waiting queue.

func (c *Cond) Wait() {//Wait operates on pointers, pointing to memory
   c.checker.check()
   t := runtime_notifyListAdd(&c.notify)//See the name to know the meaning, add the wakeable property of Cond to the wakeable queue
   cLUnlock()//Release for a short time here, and put the pointer of the key attribute of Cond into the waiting queue,
   runtime_notifyListWait(&c.notify, t)
   c.L.Lock()
}

An understanding of why lock release is required here: Can't the one waiting for the runtime be a Ctrip that holds the lock? ? ? ? ?

func (c *copyChecker) check() {//The function of this checker is that the address of the pointer and value reference of c is the same, if the step is the same, it means that it has been copied.
   if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&
      !atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&
      uintptr(*c) != uintptr(unsafe.Pointer(c)) {
      panic("sync.Cond is copied")
   }
}

The process of Signl and the process of Broadcast both use the same pointer to indicate the runtime method of the call, which proves that they use the same pointer as a mark for waiting storage. As for why he can have such an effect, follow-up development is needed.

Guess you like

Origin blog.csdn.net/weixin_40669549/article/details/88544181