Golang中如何实现Stdout和Stderr的线程安全操作
Golang中如何实现Stdout和Stderr的线程安全操作 我在这里描述了这个问题:
Thread-safe operation with Stdout and Stderr (exec. Cmd)
问题内容: 你使用的是哪个 Go 版本 (go version)? go version go1.16.4 windows/amd64 这个问题在最新版本中是否重现? 我不知道 什么…
请告诉我应该使用哪个线程安全的缓冲区?
3 回复
type lockedReader struct {
mu sync.Mutex
r io.Reader
}
func (r *lockedReader) Read(b []byte) (n int, err error) {
r.mu.Lock()
defer r.mu.Unlock()
return r.r.Read(b)
}
type lockedWriter struct {
mu sync.Mutex
w io.Writer
}
func (w *lockedWriter) Write(b []byte) (n int, err error) {
w.mu.Lock()
defer w.mu.Unlock()
return w.w.Write(b)
}
func main() {
stdout := &lockedWriter{w: os.Stdout}
stdin := &lockedReader{r: os.Stdin}
// 使用 stdout 和 stdin 替代 os.Stdout 和 os.Stdin。
}
在Go中实现os.Stdout和os.Stderr的线程安全操作,通常需要使用互斥锁(sync.Mutex)或原子操作来保护并发访问。由于标准输出和标准错误是共享资源,多个goroutine同时写入会导致输出混乱。
以下是一个示例,展示如何使用互斥锁来确保线程安全的写入操作:
package main
import (
"fmt"
"io"
"os"
"sync"
)
// 定义一个线程安全的writer结构
type safeWriter struct {
mu sync.Mutex
w io.Writer
}
// 实现io.Writer接口的Write方法,使用互斥锁保护
func (sw *safeWriter) Write(p []byte) (n int, err error) {
sw.mu.Lock()
defer sw.mu.Unlock()
return sw.w.Write(p)
}
func main() {
// 创建线程安全的stdout和stderr writer
safeStdout := &safeWriter{w: os.Stdout}
safeStderr := &safeWriter{w: os.Stderr}
// 启动多个goroutine同时写入
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Fprintf(safeStdout, "Goroutine %d: stdout message\n", id)
fmt.Fprintf(safeStderr, "Goroutine %d: stderr message\n", id)
}(i)
}
wg.Wait()
}
如果你需要替换全局的os.Stdout和os.Stderr,可以使用os.Stdout = safeStdout和os.Stderr = safeStderr来重定向。但注意这会影响所有使用这些变量的代码。
对于exec.Cmd,你可以直接设置Cmd.Stdout和Cmd.Stderr为线程安全的writer:
cmd := exec.Command("some-command")
cmd.Stdout = safeStdout
cmd.Stderr = safeStderr
err := cmd.Run()
这样能确保命令输出的线程安全性。

