package main import ( "fmt" "log" "net/http" "os" "time" ) var Q []string func main() { go func() { time.Sleep(1 * time.Second) for { test() } }() Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") time.Sleep(3 * time.Second) Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") time.Sleep(3 * time.Second) Q = append(Q, "233") time.Sleep(3 * time.Second) Q = append(Q, "233") http.HandleFunc("/", handle) err := http.ListenAndServe(":8080", nil) if err != nil { log.Println("http port has been used.") os.Exit(-1) } } func handle(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() _ = r.ParseForm() _, _ = fmt.Fprint(w, "hello") } func test() { file := queueOut() if file != "" { log.Println(file) } } func queueOut() string { res := Q[0] if len(Q) == 1 { Q[0] = "" return res } Q = Q[1:] return res }
我觉得我这样写没错啊. 但是运行的时候有几率出现
panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1058fe5] goroutine 19 [running]: fmt.(*buffer).WriteString(...) /opt/local/lib/go/src/fmt/print.go:82 fmt.(*fmt).padString(0xc000114040, 0x0, 0x3) /opt/local/lib/go/src/fmt/format.go:110 +0x9d fmt.(*fmt).fmtS(0xc000114040, 0x0, 0x3) /opt/local/lib/go/src/fmt/format.go:328 +0x61 fmt.(*pp).fmtString(0xc000114000, 0x0, 0x3, 0x76) /opt/local/lib/go/src/fmt/print.go:437 +0x122 fmt.(*pp).printArg(0xc000114000, 0x1247a20, 0xc000010050, 0x76) /opt/local/lib/go/src/fmt/print.go:671 +0x878 fmt.(*pp).doPrintln(0xc000114000, 0xc0000cffa8, 0x1, 0x1) /opt/local/lib/go/src/fmt/print.go:1146 +0xb1 fmt.Sprintln(0xc0000cffa8, 0x1, 0x1, 0x1247a20, 0x1) /opt/local/lib/go/src/fmt/print.go:271 +0x52 log.Println(0xc0000cffa8, 0x1, 0x1) /opt/local/lib/go/src/log/log.go:301 +0x3f main.test() /Users/licsber/go/src/test/main.go:52 +0xd7 main.main.func1() /Users/licsber/go/src/test/main.go:17 +0x2f created by main.main /Users/licsber/go/src/test/main.go:14 +0x39 Process finished with exit code 2
小白表示无法理解 这个问题是几率出现. 每次运行不一定都有
![]() | 1 mlkr 2018-12-07 21:16:27 +08:00 要加锁吧 |
![]() | 2 AlphaTr 2018-12-07 21:18:59 +08:00 slice 的线程安全问题,加锁? |
![]() | 4 mlkr 2018-12-07 21:26:07 +08:00 ![]() package main import ( "fmt" "log" "net/http" "os" "sync" "time" ) var Q []string var lock sync.RWMutex func main() { go func() { time.Sleep(1 * time.Second) for { test() } }() Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") time.Sleep(3 * time.Second) Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") Q = append(Q, "233") time.Sleep(3 * time.Second) Q = append(Q, "233") time.Sleep(3 * time.Second) Q = append(Q, "233") http.HandleFunc("/", handle) err := http.ListenAndServe(":8080", nil) if err != nil { log.Println("http port has been used.") os.Exit(-1) } } func handle(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() _ = r.ParseForm() _, _ = fmt.Fprint(w, "hello") } func test() { file := queueOut() if file != "" { log.Println(file) } } func queueOut() string { // 加写锁 lock.Lock() res := Q[0] if len(Q) == 1 { Q[0] = "" return res } Q = Q[1:] lock.Unlock() return res } |
5 littlewing 2018-12-07 21:29:03 +08:00 有 channel 不用非要用非线程安全的 slice 另外 slice 的 append 操作是会重新分配 slice 结构的,而且你的 slice 初始 len 为 0,每次扩容时存储数据的 array 也会重新分配,问题应该就出现在这里 |
![]() | 7 Licsber OP @littlewing channel 是啥.. 刚学 go 还没看到 我去看看 谢谢 |
![]() | 8 mritd 2018-12-07 21:37:36 +08:00 via iPhone 大哥你这个 ... channel 啊 |
9 heimeil 2018-12-07 22:00:55 +08:00 Q = Q[1:]瞬间执行多次,这个并发直接把 Q 给 cut 没了,再访问 Q 的任意下标自然就崩了。 要非得用 slice 就别直接操作 slice,另外封装两个增删方法,加上锁。 |
![]() | 10 mlkr 2018-12-07 22:12:18 +08:00 @Licsber func queueOut() string { res := Q[0] if len(Q) == 1 { Q[0] = "" return res } // 加写锁 lock.Lock() Q = Q[1:] lock.Unlock() return res } |
![]() | 11 AngryPanda 2018-12-07 22:14:49 +08:00 via Android ![]() channel 没学等于没学 go |
![]() | 14 Licsber OP @AngryPanda 刚看到 go routine , 感谢 现在接触的 go 给我一种我一直在处理错误(err)的错觉 |