Deadlocks and live locks
Deadlock: it will make all concurrent programs waiting. If there is no external intervention, the program cannot be recovered
type values struct{ mu sync.Mutex value int } func TestMutes(v1, v2 *values){ defer wg.Done() v1.mu.Lock() defer v1.mu.Unlock() time.Sleep(2*time.Second) v2.mu.Lock() defer v2.mu.Unlock() fmt.Println("v1+v2=:",v1.value+v2.value) } var wg sync.WaitGroup func main(){ var a = values{ value:1, mu:sync.Mutex{}, } var b = values{ value: 2, mu:sync.Mutex{}, } wg.Add(2) go TestMutes(&a,&b) go TestMutes(&b,&a) wg.Wait() } fatal error: all goroutines are asleep - deadlock!
Deadlock occurs due to time problem. Code running time:
There are four ways to detect, prevent and correct deadlocks:
- Mutual exclusion: concurrent processes have exclusive rights to resources at the same time
- Wait condition: concurrent processes must have one resource at the same time and wait for additional resources
- No preemption: resources owned by a concurrent process can only be released by the process
- Cyclic waiting: a concurrent process p1 must wait for a series of other concurrent processes p2, p2 is also waiting for p1
The resources of goroutine in the above code cannot be achieved (no preemption)
Livelock: a program that is actively executing concurrent operations, but these operations cannot advance the state of the program
//Simulation of people passing through the corridor func main(){ cadence := sync.NewCond(&sync.Mutex{}) go func(){ for range time.Tick(1 *time.Millisecond){ cadence.Broadcast() } }() takeStep := func(){ cadence.L.Lock() cadence.Wait() cadence.L.Unlock() } //tryDir allows a person to try to move in one direction tryDir := func(dirName string, dir *int32, out *bytes.Buffer)bool{ fmt.Fprintf(out,"%v",dirName) atomic.AddInt32(dir,1)//Move in one direction takeStep() //Everyone moves at the same pace if atomic.LoadInt32(dir)==1{ fmt.Fprintf(out,".Success!") return true } takeStep() atomic.AddInt32(dir,-1)//It means you can't leave return false } var left, right int32 tryLeft := func(out *bytes.Buffer)bool{return tryDir(" left ",&left,out)} tryRight := func(out *bytes.Buffer) bool{return tryDir(" right ",&right,out)} walk := func(walking *sync.WaitGroup, name string){ var out bytes.Buffer defer func() {fmt.Println(out.String())}() defer walking.Done() fmt.Fprintf(&out, "%v is trying to scoot:",name) for i := 0; i < 5; i++{//Limit the number of attempts if tryLeft(&out) || tryRight(&out){//First try to the left return } } fmt.Fprintf(&out,"\n%v hello!",name) } var peopleIn sync.WaitGroup//Simulate two people peopleIn.Add(2) go walk(&peopleIn,"tom") go walk(&peopleIn,"alice") peopleIn.Wait() } //Result: //alice is trying to scoot: left right left right left right left right left right alice hello! tom is trying to scoot: left right left right left right left right left right tom hello! tom and alice Will continue to compete before exiting