我应该把“mutex”放在哪里才能从 Go 的切片中删除元素?父结构还是子结构?

Where should I put `mutex` in order to delete an element from a slice in Go? The parent or child struct?

提问人:baris 提问时间:7/26/2023 最后编辑:Peter Mortensenbaris 更新时间:7/28/2023 访问量:76

问:

假设我有两个结构,如下所示:

type Device struct {
     Ports []*TCPPort
}

type TCPPort struct {
     ID int
     State bool
     Device *Device
}

创建 a 时,将按如下方式追加:TCPPort

// Body of the `createTCPPort is intentionally left blank. Imagine it creates a port and returns it.`
func createTCPPort() *TCPPort {}
tcp := createTCPPort()
device.Ports = append(device.Ports, tcp)

在任何给定时间,都会请求删除其中一个 TCP 端口。我想从这个切片中删除/移除这个端口,在那里我通过设备附加了这些端口。港口。目前我猜这个操作是否按顺序进行并不重要。我很困惑我应该把和使用它的功能放在哪里,它们是 和 .Ports []*TCPPortMutexlockunlock

我应该像下面这样把它放在结构体中吗?Device

type Device struct {
     portMutex  sync.Mutex
     Ports []*TCPPort
}

// And then remove the element as follows:?
func (d Device) removePortFromSlice(){
    d.portMutex.Lock()
    defer d.portMutex.Lock()
    // Remove slice operation here
}

type TCPPort struct {
     PortMutex sync.Mutex
     ID int
     State bool
     Device *Device
}

func (tcp TCPPort) removeElementFromSlice() {
    tcp.portMutex.Lock()
    defer tcp.portMutex.Lock()
    // Remove operation here
}

我应该将互斥锁放入父结构体还是子结构体中?DeviceTCPPort

go 结构 同步 切片互 斥锁

评论


答:

0赞 TiGo 7/26/2023 #1

由于端口切片是设备结构上的一个字段,因此将互斥锁放在设备中以同步对该特定字段的访问是有意义的。

以下是有关使用互斥锁的建议:

type Device struct {
  portMutex sync.Mutex
  Ports     []*TCPPort 
}

func (d *Device) RemovePort(port *TCPPort) {

  d.portMutex.Lock()
  defer d.portMutex.Unlock()

  // Find index of port to remove
  index := -1
  for i, p := range d.Ports {
    if p == port {
      index = i
      break
    }
  }

  // Remove from slice
  if index != -1 {
    d.Ports = append(d.Ports[:index], d.Ports[index+1:]...) 
  }

}

这将锁定对端口切片的访问,特别是在删除项目时。

将互斥锁放在 TCPPort 上效果不佳,因为即使每个 TCPPort 结构都将被锁定,Device 中的切片仍可由其他 goroutine 同时修改。 关键是同步对需要并发访问保护的共享数据结构的访问。

-3赞 Mohammad Safakhou 7/26/2023 #2

是的,可以使用互斥锁安全地处理对设备结构中端口切片的并发访问。将互斥锁放在设备结构中是一种合理的方法。

下面介绍如何修改设备结构并添加方法,以使用互斥锁安全地添加和删除 TCP 端口:

    import "sync"

type Device struct {
    Ports []*TCPPort
    mu    sync.Mutex // Mutex to protect access to Ports
}

type TCPPort struct {
    ID     int
    State  bool
    Device *Device
}

// Method to add a TCP port to the Device's Ports slice safely
func (d *Device) AddPort(tcp *TCPPort) {
    d.mu.Lock()
    defer d.mu.Unlock()
    d.Ports = append(d.Ports, tcp)
}

// Method to remove a TCP port from the Device's Ports slice safely
func (d *Device) RemovePort(tcp *TCPPort) {
    d.mu.Lock()
    defer d.mu.Unlock()

    // Find the index of the TCP port in the Ports slice
    var index int
    for i, port := range d.Ports {
        if port == tcp {
            index = i
            break
        }
    }

    // Remove the TCP port from the slice
    d.Ports = append(d.Ports[:index], d.Ports[index+1:]...)
}

现在,当您要添加或删除 TCP 端口时,可以分别使用 Device 结构的 AddPort 和 RemovePort 方法执行此操作。互斥锁确保一次只有一个 goroutine 可以修改 Ports 切片,从而提供并发安全性。

评论

2赞 DavidW 7/27/2023
这个答案看起来像 ChatGPT