Go concurrent programming -- deadlock and livelock

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

Posted by warpdesign on Mon, 04 Nov 2019 11:11:47 -0800