你应该使用通道(channel)还是sync.Mutex的lock()方法?

huangapple go评论84阅读模式
英文:

should I use a channel or a sync.Mutex lock()?

问题

在执行go test -race时,我发现在命令开始之前就调用了os.Process.Kill,我提出了两种可能的解决方案,一种是使用channel

package main

import "os/exec"

func main() {
    cmd := exec.Command("sleep", "10")
    started := make(chan struct{}, 1)

    go func() {
        <-started
        cmd.Process.Kill()
    }()

    if err := cmd.Start(); err != nil {
        panic(err)
    }
    started <- struct{}{}

    cmd.Wait()
}

另一种是使用lock

package main

import (
    "os/exec"
    "sync"
)

func main() {
    var lock sync.Mutex
    cmd := exec.Command("sleep", "10")

    lock.Lock()
    if err := cmd.Start(); err != nil {
        panic(err)
    }
    lock.Unlock()
    go func() {
        cmd.Process.Kill()
    }()

    cmd.Wait()
}

这两种方法都可以工作,但想知道哪种方法更符合惯用方式或更好,主要目标是防止杀死尚未启动的进程。

英文:

While doing a go test -race, I found that a call to os.Process.Kill, was made before the command started cmd.Start(), I came with to posible solutions, one to use a channel:

package main

import &quot;os/exec&quot;

func main() {
	cmd := exec.Command(&quot;sleep&quot;, &quot;10&quot;)
	started := make(chan struct{}, 1)

	go func() {
		&lt;-started
		cmd.Process.Kill()
	}()

	if err := cmd.Start(); err != nil {
		panic(err)
	}
	started &lt;- struct{}{}

	cmd.Wait()
}

or to use a lock:

package main

import (
    &quot;os/exec&quot;
    &quot;sync&quot;
)

func main() {
	var lock sync.Mutex
	cmd := exec.Command(&quot;sleep&quot;, &quot;10&quot;)

	lock.Lock()
	if err := cmd.Start(); err != nil {
		panic(err)
	}
	lock.Unlock()
	go func() {
		cmd.Process.Kill()
	}()

	cmd.Wait()
}

Both options work but wondering what could be the most idiomatic or better approach, while the main goal is just to prevent killing a process that hasn't been started.

答案1

得分: 0

我建议你使用一个通道,但是让我指出一些关于你的代码的问题。

我注意到你使用了一个带缓冲的通道,并且在调用消费通道的 goroutine 之前先向该通道发送数据。在我看来,以下做法可能更好:

1)在这种情况下,使用一个无缓冲的通道进行信号传递会更好。

2)让 goroutine 负责启动进程并调用等待函数,同时向主函数发出已启动的信号。

代码示例如下:

package main

import "os/exec"

func main() {

    cmd := exec.Command("sleep", "10")
    started := make(chan struct{})

    go func(cmd *exec.Cmd, signal chan struct{}) {
        if err := cmd.Start(); err != nil {
            panic(err)
        }
        
        started <- struct{}{}
        cmd.Wait()
    }(cmd, started)
    
    <-started
    cmd.Process.Kill()
}

以上是翻译好的内容,请确认是否满意。

英文:

I would suggest you use a channel, but let me point out something about your code.

I noticed you used a buffered channel, and then sent data on that channel first, before calling the goroutine that consumes the channel. In my opinion, it would be better to:

  1. use an unbuffered channel for signalling, especially in this case.

  2. Have the goroutine be responsible for starting the process and calling wait, while signaling to the main that it has started.

Like this:

package main

import &quot;os/exec&quot;

func main() {

    cmd := exec.Command(&quot;sleep&quot;, &quot;10&quot;)
    started := make(chan struct{})

    go func(cmd *exec.Cmd, signal chan struct{}) {
        if err := cmd.Start(); err != nil {
            panic(err)
        }
        
        started &lt;- struct{}{}
        cmd.Wait()
    }(cmd, started)
    
    &lt;-started
    cmd.Process.Kill()
}

huangapple
  • 本文由 发表于 2016年8月21日 01:59:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/39057184.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定