go - 如果我要返回变量的副本而不是指针,是否需要互斥体?

标签 go concurrency mutex

我对在 Go 中使用 sync.Mutex 有点困惑。我理解基本概念(调用 Lock() 将阻止其他 goroutines 执行它和 Unlock() 之间的代码),但我不确定我是否 需要这里。我已经看到了相当多的 C++ 答案,但在每个示例中,它们似乎都在直接修改和访问变量。

这是我的代码,来自一个名为配置的包,我将在整个应用程序中使用它来获取(令人惊讶的)配置和设置信息。

package config

import (
    "encoding/json"
    "fmt"
    "os"
    "sync"

    log "github.com/sirupsen/logrus"
)

/*
ConfigurationError is an implementation of the error interface describing errors that occurred while dealing with this
package.
*/
type ConfigurationError string

/*
Error prints the error message for this ConfigurationError. It also implements the error interface.
*/
func (ce ConfigurationError) Error() string {
    return fmt.Sprintf("Configuration error: %s", string(ce))
}

/*
configuration is a data struct that holds all of the required information for setting up the program. It is unexported
to prevent other packages creating more instances. Other packages that need settings information should call Current()
to access a copy of the unexported programConfig package variable.
*/
type configuration struct {
    sync.RWMutex
    LogLevel               log.Level `json:"logLevel,omitempty"`     //Logging
    LogLocation            string    `json:"logLocation,omitempty"`  //-
    HttpPort               int       `json:"port,omitempty"`         //Web
    LoginUri               string    `json:"loginUri"`               //-
    WebBaseUri             string    `json:"webBaseUri"`             //-
    StaticBaseUri          string    `json:"staticBaseUri"`          //-
    ApiBaseUri             string    `json:"apiBaseUri"`             //-
    StaticContentLocalPath string    `json:"staticContentLocalPath"` //-
    MaxSimultaneousReports int       `json:"maxSimultaneousReports"` //Reporting
}

var programConfig configuration

/*
Current returns a copy of the currently loaded program configuration.
*/
func Current() configuration {
    programConfig.RLock()
    defer programConfig.RUnlock()
    return programConfig
}

/*
Load attempts to load a JSON settings file containing a representation of the Configuration struct. It will then set
the value of the package-level config struct to the loaded values. Some settings changes will require a restart of the
server application.

filepath - the full path of the settings file including a leading slash or drive name (depending on the OS).
*/
func Load(filepath string) error {

    //Open the file for reading.
    settingsFile, err := os.Open(filepath)
    if err != nil {
        return ConfigurationError(err.Error())
    }
    defer settingsFile.Close()

    //Decode JSON into package level var.
    decoder := json.NewDecoder(settingsFile)
    newSettings := configuration{}
    err = decoder.Decode(&newSettings)
    if err != nil {
        return ConfigurationError(err.Error())
    }

    programConfig.Lock() //I'm not 100% sure this is the correct use of a mutex for this situation, so check up on that.
    programConfig = newSettings
    programConfig.Unlock()
    return nil

}

如您所见,我在两个地方使用了互斥锁。

  • Current() 中。如果函数返回的不是指针而是 programConfig 变量的副本,我是否需要在此处执行此操作?修改底层包变量的唯一方法是通过 Load() 函数。
  • Load() 函数中。任何 goroutine 都可以随时调用它,尽管这种情况很少见。

鉴于此,我是否正确使用了它们?为什么在读取数据副本时需要一个(如果需要)?

最佳答案

当您读取可以同时写入的数据时,您需要一个互斥量。否则可能会发生边读边写,得到一半旧数据和一半新数据的情况。

所以你的例子似乎很好。因为您可能经常阅读配置但很少编写配置,所以您对 RWLock 的使用很有意义。这意味着只要不写入,多个线程可以同时读取。

在您的代码中看起来危险的是:

programConfig.Lock()
programConfig = newSettings
programConfig.Unlock()

因为 programConfig 包含 Mutex 你在不同的实例上执行 LockUnlock 这将导致僵局。您应该将 Mutex 添加到实例的“父级”。在这种情况下可能是包。

关于go - 如果我要返回变量的副本而不是指针,是否需要互斥体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41976512/

相关文章:

Go time.Tick 与 time.NewTicker

multithreading - golang 应用程序运行时保留了很多线程

go - 如何发送动态 json 键/值作为请求参数

sql-server - SQL Server 2008 : Getting deadlocks. ..没有任何锁

c - 缩短线程安全(不平衡)二叉树中的关键部分

c - 当互斥体可用时在哪里使用二进制信号量?

戈朗。用什么? http.ServeFile(..) 还是 http.FileServer(..)?

java - 客户端线程挂起模拟会阻止服务器在客户端设置等待期间接受任何 I/O

Java - 在使用 JButton 执行时暂停线程池

C++如何在银行账户转账时避免竞争条件