golang--使用channel来同步goroutine

在golang中同步goroutine有2种方法,要么使用channel,要么使用sync.WaitGroup,本文就是介绍如何通过channel来同步goroutine。先看代码。

 1 package main

 2 

 3 import (

 4     "os"

 5     "os/signal"

 6     "runtime"

 7     "log"

 8     "syscall"

 9 )

10 

11 const NUM_OF_QUIT int = 100

12 

13 func main() {

14     runtime.GOMAXPROCS(runtime.NumCPU())

15     done := make(chan bool)

16     receive_channel := make(chan chan bool)

17     finish := make(chan bool)

18 

19 

20     for i := 0; i < NUM_OF_QUIT; i++ {

21         go do_while_select(i, receive_channel, finish)

22     }

23 

24     go handle_exit(done, receive_channel, finish)

25 

26     <-done

27     os.Exit(0)

28 

29 }

30 func handle_exit(done chan bool, receive_channel chan chan bool, finish chan bool) {

31     sigs := make(chan os.Signal, 1)

32     signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

33     chan_slice := make([]chan bool, 0)

34     for {

35         select {

36         case  <-sigs:

37             for _, v := range chan_slice {

38                 v <- true

39             }

40             for i := 0; i < len(chan_slice); i++ {

41                 <-finish

42             }

43             done <- true

44             runtime.Goexit()

45         case single_chan := <-receive_channel:

46             log.Println("the single_chan is ", single_chan)

47             chan_slice = append(chan_slice, single_chan)

48         }

49     }

50 }

51 func do_while_select(num int, rece chan chan bool, done chan bool) {

52     quit := make(chan bool)

53     rece <- quit

54     for {

55         select {

56         case <-quit:

57             done <- true

58             runtime.Goexit()

59         default:

60             //简单输出

61             log.Println("the ", num, "is running")

62         }

63     }

64 }

上面的代码保存为example.go,通过gotool编译代码:

go build example.go

在当前目录下有example文件,在终端运行这个文件

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running

2013/03/19 21:17:14 the  0 is running
......

上面不断输出goroutine中的数字,等待退出信号。

新打开一个终端,通过ps找到这个进程名,通过kill工具干掉这个进程:

$ps aux | grep example

user  4026 77.9  0.0  39436  1716 pts/1    Sl+  21:19   0:17 ./example

$kill 4026

不久就可以看到在第一个终端里面不再打印,至此演示完毕。

代码思想:

新建NUM_OF_QUIT个goroutine,这些个goroutine里面新建1个chan bool,通过这个channel来接受退出的信号,这些channel在新建的时候,已经发给了handle_exit。在handle_exit这个goroutine里面,1方面监控由系统发过来的退出信号,然后再通知其他的goroutin优雅地退出;另一方面通过slice收集其他goroutine发过来的channel。handle_exit通知其他的goroutine优雅退出后,再发信号给main进程主动退出。

可以修改NUM_OF_QUIT值,例如改为10000,这个时候,kill命令发出去后,要等待相当长的一段时间才能看到第一个终端停止打印。

参考:

Go by Example: Signals

https://gobyexample.com/signals

 转贴请注明来自:格通

 

你可能感兴趣的:(channel)