2 回答

TA貢獻1876條經驗 獲得超7個贊
此代碼中有許多爭用條件。一般來說,如果你創建一個 goroutine,應該有某種同步 -- 如 、 、 或原子。chan
sync.Mutex
sync.WaitGroup
修復爭用條件。
呼叫之前先呼叫 。代碼不這樣做。
StderrPipe()
Start()
等待戈魯丁完成,然后再返回。
競爭條件可能會破壞結構...這可能意味著它泄漏了一根管道,這可以解釋為什么掛起(因為管道的寫入端沒有關閉)。exec.Cmd
Read()
根據經驗,請始終修復爭用條件。將它們視為高優先級 Bug。
以下是如何在沒有競爭條件的情況下編寫它的草圖:

TA貢獻1818條經驗 獲得超7個贊
func runProcess(process *exec.Cmd) (stdout, stderr string, err error) {
outPipe, err := process.StdoutPipe()
if err != nil {
return "", "", err
}
// Call StderrPipe BEFORE Start().
// Easy way to do it: outside the goroutine.
errPipe, err := process.StderrPipe()
if err != nil {
return "", "", err
}
// Start process.
if err := process.Start(); err != nil {
return "", "", err
}
// Read stderr in goroutine.
var wg sync.WaitGroup
var stderrErr error
wg.Add(1)
go func() {
defer wg.Done()
data, err := ioutil.ReadAll(errPipe)
if err != nil {
stderrErr = err
} else {
stderr = string(data)
}
}()
// Read stdout in main thread.
data, stdoutErr := ioutil.ReadAll(outPipe)
// Wait until we are done reading stderr.
wg.Wait()
// Wait for process to finish.
if err := process.Wait(); err != nil {
return "", "", err
}
// Handle error from reading stdout.
if stdoutErr != nil {
return "", "", stderrErr
}
// Handle error from reading stderr.
if stderrErr != nil {
return "", "", stderrErr
}
stdout = string(data)
return stdout, stderr, nil
}
更簡單的代碼
所有這些都是由包自動完成的。您可以使用 任何 for 和 ,您不限于 。os/execio.WriterStdoutStderr*os.File
func runProcess(process *exec.Cmd) (stdout, stderr string, err error) {
var stdoutbuf, stderrbuf bytes.Buffer
process.Stdout = &stdoutbuf
process.Stderr = &stderrbuf
if err := process.Run(); err != nil {
return "", "", err
}
return stdoutbuf.String(), stderrbuf.String(), nil
}
- 2 回答
- 0 關注
- 107 瀏覽
添加回答
舉報