作为我的第一个 golang 项目,我正在开发一个 slack bot,虽然这个特定的 bot 命令的功能很好,但它可能会随机恐慌并引发错误。
我能够确定我正在进行数据竞赛,特别是我的两个 go 例程。但是我很难确定如何修补它们,或者做互斥锁是否是处理共享变量的正确方法。
我试图弄清楚问题是我的结果变量,它被分成通道,每个通道都由 go 例程处理,或者它是我的缓冲区变量,os.exec 包使用它来运行两个标准输出的命令和 stderr 修改。
这是下面的代码和数据竞争示例。
package reboot
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os/exec"
"regexp"
)
// to handle json keys
type rebootObject struct {
Name string
Command string
}
var (
fileNotFound = "config file not found"
cmdNotFound = "Error finding command argument"
)
// *bot.Cmd is the first arg to be passed to the bot
// bot.CmdResultV3 wants message from go routine and done = true
func Reboot(command *bot.Cmd) (result bot.CmdResultV3, err error) {
result = bot.CmdResultV3{Message: make(chan string), Done: make(chan bool, 1)}
// load json config file with names/commands
filePath := "./plugins/reboot/config.json"
file, err1 := ioutil.ReadFile(filePath)
if err1 != nil {
bot.Reply(command.Channel, fileNotFound, command.User)
}
var scriptParse []rebootObject
//userinput := "box4535345346" // faking user input
userinput := command.Args[0] // real one
err2 := json.Unmarshal(file, &scriptParse)
if err2 != nil {
fmt.Println("error:", err2)
bot.Reply(command.Channel, fileNotFound, command.User)
}
//strip numbers off input to match json key
reg, err := regexp.Compile("[^a-zA-Z]+")
if err != nil {
log.Fatal(err)
}
// loop through json file to find the match of user input to json name key
cmdFound := false
for k := range scriptParse {
newinput := reg.ReplaceAllString(userinput, "")
// keep running for loop until names do match
if scriptParse[k].Name != newinput {
continue
}
cmdFound = true
cmd := exec.Command("/bin/bash", "-c", scriptParse[k].Command)
var b bytes.Buffer
cmd.Stdout = &b
cmd.Stderr = &b
err = cmd.Start()
if err != nil {
return
}
done := false
go func() {
cmd.Wait()
done = true
result.Done <- true
}()
go func() {
for {
line, _ := b.ReadString('\n')
if line != "" {
result.Message <- line
}
if done {
close(result.Message)
break
}
}
}()
}
if cmdFound == false {
result.Done <- true
bot.Reply(command.Channel, cmdNotFound, command.User)
}
return result, nil
}
数据竞赛:
==================
WARNING: DATA RACE
Read at 0x00c420582558 by goroutine 37:
bytes.(*Buffer).readSlice()
/usr/local/go/src/bytes/buffer.go:421 +0x48
bytes.(*Buffer).ReadString()
/usr/local/go/src/bytes/buffer.go:440 +0x45
github.com/owner/gobot/plugins/reboot.Reboot.func2()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:79 +0x41
Previous write at 0x00c420582558 by goroutine 35:
bytes.(*Buffer).ReadFrom()
/usr/local/go/src/bytes/buffer.go:92 +0x608
io.copyBuffer()
/usr/local/go/src/io/io.go:386 +0x348
io.Copy()
/usr/local/go/src/io/io.go:362 +0x7e
os/exec.(*Cmd).writerDescriptor.func1()
/usr/local/go/src/os/exec/exec.go:264 +0x68
os/exec.(*Cmd).Start.func1()
/usr/local/go/src/os/exec/exec.go:380 +0x34
Goroutine 37 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:77 +0x885
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
Goroutine 35 (running) created at:
os/exec.(*Cmd).Start()
/usr/local/go/src/os/exec/exec.go:379 +0xa6b
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:67 +0x7c8
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
==================
==================
WARNING: DATA RACE
Read at 0x00c420582540 by goroutine 37:
bytes.(*Buffer).readSlice()
/usr/local/go/src/bytes/buffer.go:421 +0x62
bytes.(*Buffer).ReadString()
/usr/local/go/src/bytes/buffer.go:440 +0x45
github.com/owner/gobot/plugins/reboot.Reboot.func2()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:79 +0x41
Previous write at 0x00c420582540 by goroutine 35:
bytes.(*Buffer).ReadFrom()
/usr/local/go/src/bytes/buffer.go:91 +0x5d0
io.copyBuffer()
/usr/local/go/src/io/io.go:386 +0x348
io.Copy()
/usr/local/go/src/io/io.go:362 +0x7e
os/exec.(*Cmd).writerDescriptor.func1()
/usr/local/go/src/os/exec/exec.go:264 +0x68
os/exec.(*Cmd).Start.func1()
/usr/local/go/src/os/exec/exec.go:380 +0x34
Goroutine 37 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:77 +0x885
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
Goroutine 35 (running) created at:
os/exec.(*Cmd).Start()
/usr/local/go/src/os/exec/exec.go:379 +0xa6b
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:67 +0x7c8
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
==================
==================
WARNING: DATA RACE
Write at 0x00c420582560 by goroutine 37:
bytes.(*Buffer).readSlice()
/usr/local/go/src/bytes/buffer.go:429 +0x186
bytes.(*Buffer).ReadString()
/usr/local/go/src/bytes/buffer.go:440 +0x45
github.com/owner/gobot/plugins/reboot.Reboot.func2()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:79 +0x41
Previous write at 0x00c420582560 by goroutine 35:
bytes.(*Buffer).ReadFrom()
/usr/local/go/src/bytes/buffer.go:191 +0x5f
io.copyBuffer()
/usr/local/go/src/io/io.go:386 +0x348
io.Copy()
/usr/local/go/src/io/io.go:362 +0x7e
os/exec.(*Cmd).writerDescriptor.func1()
/usr/local/go/src/os/exec/exec.go:264 +0x68
os/exec.(*Cmd).Start.func1()
/usr/local/go/src/os/exec/exec.go:380 +0x34
Goroutine 37 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:77 +0x885
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
Goroutine 35 (running) created at:
os/exec.(*Cmd).Start()
/usr/local/go/src/os/exec/exec.go:379 +0xa6b
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:67 +0x7c8
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
==================
==================
WARNING: DATA RACE
Read at 0x00c42014cc00 by goroutine 37:
runtime.slicebytetostring()
/usr/local/go/src/runtime/string.go:72 +0x0
bytes.(*Buffer).ReadString()
/usr/local/go/src/bytes/buffer.go:441 +0x84
github.com/owner/gobot/plugins/reboot.Reboot.func2()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:79 +0x41
Previous write at 0x00c42014cc00 by goroutine 35:
internal/race.WriteRange()
/usr/local/go/src/internal/race/race.go:49 +0x42
syscall.Read()
/usr/local/go/src/syscall/syscall_unix.go:165 +0x9a
internal/poll.(*FD).Read()
/usr/local/go/src/internal/poll/fd_unix.go:122 +0x1a0
os.(*File).read()
/usr/local/go/src/os/file_unix.go:216 +0x70
os.(*File).Read()
/usr/local/go/src/os/file.go:103 +0x8e
bytes.(*Buffer).ReadFrom()
/usr/local/go/src/bytes/buffer.go:209 +0x1dd
io.copyBuffer()
/usr/local/go/src/io/io.go:386 +0x348
io.Copy()
/usr/local/go/src/io/io.go:362 +0x7e
os/exec.(*Cmd).writerDescriptor.func1()
/usr/local/go/src/os/exec/exec.go:264 +0x68
os/exec.(*Cmd).Start.func1()
/usr/local/go/src/os/exec/exec.go:380 +0x34
Goroutine 37 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:77 +0x885
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
Goroutine 35 (running) created at:
os/exec.(*Cmd).Start()
/usr/local/go/src/os/exec/exec.go:379 +0xa6b
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:67 +0x7c8
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
==================
==================
WARNING: DATA RACE
Read at 0x00c4202d2600 by goroutine 37:
runtime.slicebytetostring()
/usr/local/go/src/runtime/string.go:72 +0x0
bytes.(*Buffer).ReadString()
/usr/local/go/src/bytes/buffer.go:441 +0x84
github.com/owner/gobot/plugins/reboot.Reboot.func2()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:79 +0x41
Previous write at 0x00c4202d2600 by goroutine 35:
runtime.slicecopy()
/usr/local/go/src/runtime/slice.go:160 +0x0
bytes.(*Buffer).ReadFrom()
/usr/local/go/src/bytes/buffer.go:205 +0x4b2
io.copyBuffer()
/usr/local/go/src/io/io.go:386 +0x348
io.Copy()
/usr/local/go/src/io/io.go:362 +0x7e
os/exec.(*Cmd).writerDescriptor.func1()
/usr/local/go/src/os/exec/exec.go:264 +0x68
os/exec.(*Cmd).Start.func1()
/usr/local/go/src/os/exec/exec.go:380 +0x34
Goroutine 37 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:77 +0x885
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
Goroutine 35 (running) created at:
os/exec.(*Cmd).Start()
/usr/local/go/src/os/exec/exec.go:379 +0xa6b
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:67 +0x7c8
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
==================
==================
WARNING: DATA RACE
Write at 0x00c4202008c8 by goroutine 36:
github.com/owner/gobot/plugins/reboot.Reboot.func1()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:74 +0x4d
Previous read at 0x00c4202008c8 by goroutine 37:
github.com/owner/gobot/plugins/reboot.Reboot.func2()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:83 +0x61
Goroutine 36 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:72 +0x846
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
Goroutine 37 (running) created at:
github.com/owner/gobot/plugins/reboot.Reboot()
/Users/macowner/go/src/github.com/owner/gobot/plugins/reboot/reboot.go:77 +0x885
github.com/owner/gobot/bot.(*Bot).handleCmd()
/Users/macowner/go/src/github.com/owner/gobot/bot/cmd.go:240 +0x13b
github.com/owner/gobot/bot.(*Bot).MessageReceived()
/Users/macowner/go/src/github.com/owner/gobot/bot/bot.go:101 +0x5a8
github.com/owner/gobot/bot.Run()
/Users/macowner/go/src/github.com/owner/gobot/bot/reply.go:142 +0xdb3
main.main()
/Users/macowner/go/src/github.com/owner/gobot/main.go:46 +0x9b0
==================