7

1. Using sync.WaitGroup

A sync.WaitGroup is a way to coordinate multiple goroutines by reporting completion. Since there’s nobody to report completion, it never returns. Wait blocks until the WaitGroup counter is zero.

package main

import "sync"

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    wg.Wait()
}

2. Empty select

This function tries to select the first case that returns, so it will happily wait forever for nothing to return.

package main

func main() {
    select{}
}

3. Double Locking

If the lock is already in use, the calling goroutine blocks until the mutex is available.

package main

import "sync"

func main() {
    var m sync.Mutex
    m.Lock()
    m.Lock()
}

The same trick works with a sync.RWMutex that has been RLock()’d.

4. Empty Channel

Empty channels will block until there is something to receive.

package main

func main() {
    c := make(chan struct{})
    <-c
}

This also works with a nil channel not made with make()

5. Infinite loop

The easiest way which will use 100% of CPU.

package main

func main() {
    for {}
}

6. goto

package main

func main() {
start:
    goto start
}

7. defer

func main() {
    defer main()
}

8. Busy Blocking

This method technically doesn’t block, it just constantly defers to other work if it’s available.

package main

import "runtime"

func main() {
    for {
        runtime.Gosched()
    }
}

9. The Decomposed Loop

Same as before, not technically blocking but looping and deferring to other work.

package main

import "runtime"

func main() {
foo:
    runtime.Gosched()
    goto foo
}

10. Shaking my Own Hand

This is a bit like shaking your own hand. This function will continually send a useless message to itself until the end of time. The channel send operations are opportunities for the runtime to schedule other goroutines, so this method would not monopolize a single processor.

package main

func main() {
    c := make(chan struct{}, 1)
    for {
        select {
        case <-c:
        case c <- struct{}{}:
        }
    }
}

11. Sleeping for a Looooong Time

Sleeping to the maximum time allowed takes quite a long time, roughly 292.4 years. Likely, your code won’t run that long, so I’d consider this equivalent to select{}.

package main

import (
    "math"
    "time"
)

func main() {
    <-time.After(time.Duration(math.MaxInt64))

}

12. Signal

package main

import (
    "os"
    "os/signal"
    "syscall"
)

func main() {
    // exit program on ps kill and Ctrl+C...
    exitc := make(chan os.Signal, 1)
    signal.Notify(exitc, os.Interrupt, os.Kill, syscall.SIGTERM)

    // some code or goroutines
    // ...
    <-exitc
    // some cleanup or signal logging and printing

}

总结

以上 1-4 以前都好使,现在好像不行了,会报错。

fatal error: all goroutines are asleep - deadlock!
...

参考

How to Block Forever in Go


wshi7
745 声望423 粉丝

Don't view things as static and isolated.