Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 这个Go代码是线程安全的还是我需要一个互斥锁?_Multithreading_Go_Mutex_Race Condition - Fatal编程技术网

Multithreading 这个Go代码是线程安全的还是我需要一个互斥锁?

Multithreading 这个Go代码是线程安全的还是我需要一个互斥锁?,multithreading,go,mutex,race-condition,Multithreading,Go,Mutex,Race Condition,假设我有以下函数,doWork,它在一个goroutine中开始一些工作,并返回一个结果,以检查完成情况和错误: func doWork() *Result { r := Result{doneCh: make(chan struct{})} go func() { var err error defer func() { r.err = err close(r.doneCh) }()

假设我有以下函数,
doWork
,它在一个goroutine中开始一些工作,并返回一个
结果
,以检查完成情况和错误:

func doWork() *Result {
    r := Result{doneCh: make(chan struct{})}
    go func() {
        var err error
        defer func() {
            r.err = err
            close(r.doneCh)
        }()
        // do some work
    }()
    return &r
}
其中,
Result
是以下结构:

type Result struct {
    doneCh      chan struct{}
    err         error
}
// doneCh returns a closed chan when the work is done.
func (r *Result) Done() <-chan struct{} {
    return r.doneCh
}
// Err returns a non-nil err if the work failed.
// Don't call Err until Done returns a closed chan.
func (r *Result) Err() error {
    return r.err
}

或者编译器是否可以随意排序
r.err=err
close(r.doneCh)
指令,在这种情况下,我需要一个互斥锁来防止并发读/写错误。

编译器可能不会重新排序赋值和close语句,因此,如果调用方行为良好,并且按照文档的指示操作,则不需要互斥


这在中进行了解释。

编译器可能不会对赋值和关闭语句重新排序,因此如果调用方行为良好,并且按照文档的指示执行,则不需要互斥


这在中进行了解释。

只有当您的注释得到遵守,并且在从
Done()
读取返回之前,才会调用
Err()
,这才是线程安全的

通过将其重新实现为,您可以简单地使
Err()
阻塞:

func (r *Result) Err() error {
    <-r.doneCh
    return r.err
}
func(r*Result)Err()错误{

只有当您的注释得到遵守,并且在返回从
Done()
读取之前,才会调用
Err()
,这才是线程安全的

通过将其重新实现为,您可以简单地使
Err()
阻塞:

func (r *Result) Err() error {
    <-r.doneCh
    return r.err
}
func(r*Result)Err()错误{

您是否尝试过使用
chan error
并测试接收时频道是否打开或关闭

package main

import (
    "errors"
    "fmt"
)

func delegate(work func(ch chan error)) {
    ch := make(chan error)

    go work(ch)

    for {
        err, opened := <- ch
        if !opened {
            break
        }
        // Handle errors
        fmt.Println(err)
    }
}

func main() {
    // Example: error
    delegate(func(ch chan error) {
        defer close(ch)
        // Do some work
        fmt.Println("Something went wrong.")
        ch <- errors.New("Eyyyyy")
    })

    // Example: success
    delegate(func(ch chan error) {
        defer close(ch)
        // Do some work
        fmt.Println("Everything went fine.")
    })

    // Example: error
    delegate(func(ch chan error) {
        defer close(ch)
        // Do some work
        fmt.Println("Something went wrong more than once.")
        ch <- errors.New("Eyyyyy 1")
        ch <- errors.New("Eyyyyy 2")
        ch <- errors.New("Eyyyyy 3")
    })
}
主程序包
进口(
“错误”
“fmt”
)
职能代表(工作职能(ch chan错误)){
ch:=制造(chan错误)
上班(ch)
为了{

err,opened:=您是否尝试过使用
chan error
并测试接收时频道是打开还是关闭

package main

import (
    "errors"
    "fmt"
)

func delegate(work func(ch chan error)) {
    ch := make(chan error)

    go work(ch)

    for {
        err, opened := <- ch
        if !opened {
            break
        }
        // Handle errors
        fmt.Println(err)
    }
}

func main() {
    // Example: error
    delegate(func(ch chan error) {
        defer close(ch)
        // Do some work
        fmt.Println("Something went wrong.")
        ch <- errors.New("Eyyyyy")
    })

    // Example: success
    delegate(func(ch chan error) {
        defer close(ch)
        // Do some work
        fmt.Println("Everything went fine.")
    })

    // Example: error
    delegate(func(ch chan error) {
        defer close(ch)
        // Do some work
        fmt.Println("Something went wrong more than once.")
        ch <- errors.New("Eyyyyy 1")
        ch <- errors.New("Eyyyyy 2")
        ch <- errors.New("Eyyyyy 3")
    })
}
主程序包
进口(
“错误”
“fmt”
)
职能代表(工作职能(ch chan错误)){
ch:=制造(chan错误)
上班(ch)
为了{

err,opened:=文档状态“在单个goroutine中,读取和写入必须按照程序指定的顺序执行”,所以一旦关闭了
doneCh
,就必须写入
err
。为什么要创建一个
struct
,用一个通道来表示结束并读取一些值,而不是用通道来发送值?通道通过构造是线程安全的,结构不是,利用它们。@adrio因为我使用它更像是上下文。There是从上面的示例中删除的结果的其他函数(也不称为结果),因为额外的代码与手头的问题无关。然后,您是否可以编辑您的答案以包含更多的细节(如果您愿意,请保持简单)这会使您无法使用我给您的答案?您可能可以通过通道发送比
error
更复杂的类型,以获得所需的结果。文档说明“在单个goroutine中,读取和写入必须按照程序指定的顺序执行”,所以一旦关闭了
doneCh
,就必须写入
err
。为什么要创建一个
struct
,用一个通道来表示结束并读取一些值,而不是用通道来发送值?通道通过构造是线程安全的,结构不是,利用它们。@adrio因为我使用它更像是上下文。There是从上面的示例中删除的结果的其他函数(也不称为结果),因为额外的代码与手头的问题无关。然后,您是否可以编辑您的答案以包含更多的细节(如果您愿意,请保持简单)这会阻止你使用我给你的答案吗?你可能可以通过频道发送比
error
更复杂的类型来获得你想要的结果。太好了!也谢谢你的链接,看起来像上面代码的镜像!:-)太好了!也谢谢你的链接,看起来像上面代码的镜像!:-)