golang的一個執行緒排程被停止的問題處理
阿新 • • 發佈:2018-12-27
最近發現, golang寫的遊戲伺服器, 在非除錯狀態下, 一切正常, 但是在掛接gdb除錯時, 無法收到網路訊息. 打了很多日誌, 發現, 只要有goroutine的地方, 都沒有切換進入.
回想了下, goroutine的排程規則: 1.4之前, 在碰到syscall時, goroutine會被排程並處理. 1.4後, 只要有函式呼叫時, 均會進行一次排程. 密度比以前增加了, 更加接近真執行緒的處理.
根據這個原理, 問題應該出現在伺服器底層沒有給系統提供排程機會的點上. 我們的伺服器通過一個bool型的chan進行阻塞, 讓伺服器維持阻塞進行訊息處理不退出. 但是最近為了在windows下提供命令列支援, 增加了一些程式碼, 如下
1: func WaitForExit() {
2:
3: if len(peerMap) == 0 {
4: log.Println("no peer running, exit!")
5: return
6: }
7:
8: // 命令列功能只在windows下啟用
9: if runtime.GOOS == "windows" {
10: reader := bufio.NewReader(os.Stdin)
11:
12: var running bool= true
13:
14: go func() {
15: select {
16: case <-exitChan:
17: running = false
18: }
19: }()
20:
21: for running {
22: data, _, _ := reader.ReadLine()
23: command := string(data)
24:
25: dispatchConsoleCommand(command)
26: }
27: } else {
28: // Linux環境
29: <-exitChan
30: }
31:
32: }
我暫時遮蔽了新加的這套功能, 維持<-exitChan, 問題馬上解決
結合前面的猜測, 我估計在reader.ReadLine()函式內, 沒有給底層提供排程的機會, 導致其他goroutine無法執行, 造成伺服器卡死
技術討論群: 309800774 歡迎golang愛好者加入, 純技術研討