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

 轉貼請注明來自:格通

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM