= program in which all concurrent processes are waiting on one another.
packagemainimport ("fmt""sync")funcmain() {var wg sync.WaitGroup ch1 :=make(chanint) ch2 :=make(chanint) wg.Add(1)gofunc() {defer wg.Done()// Attempting to send data to ch2, but no one is receiving. ch2 <-42 }() wg.Add(1)gofunc() {defer wg.Done()// Attempting to send data to ch1, but no one is receiving. ch1 <-23 }() wg.Wait()}
Livelocks
= programs that are actively performing concurrent operations, but these operations do nothing to move the state of the program forward.
/* Two goroutines are trying to access a shared resource (condition) protected by a mutex (mu). They repeatedly check the condition and take actions to resolve the conflict. However, their actions lead to an ongoing conflict without making progress, resulting in a livelock.*/
package mainimport ( "fmt" "sync")func main() { var mu sync.Mutex condition := true go func() { for { mu.Lock() if condition { mu.Unlock() continue } fmt.Println("Goroutine 1") condition = true mu.Unlock() } }() go func() { for { mu.Lock() if !condition { mu.Unlock() continue } fmt.Println("Goroutine 2") condition = false mu.Unlock() } }() select {}}
Starvation
= any situation where a concurrent process cannot get all the resources it needs to perform work.
/* One goroutine continually acquires and releases a lock, preventing the starving goroutine from ever acquiring it. */packagemainimport ("fmt""sync")funcmain() {var mu sync.Mutex// Starving goroutinegofunc() { mu.Lock() fmt.Println("Starving goroutine: acquired the lock") mu.Unlock() }()// Goroutine that keeps the lockgofunc() {for { mu.Lock() fmt.Println("Lock keeper goroutine: acquired the lock") mu.Unlock() } }()select {}}