【发布时间】:2021-12-07 10:04:53
【问题描述】:
您有一个结构,该结构表示一次只有一个用户可以访问的资源。可能看起来像这样:
type Resource struct{
InUse bool//or int32/int64 is you want to use atomics
Resource string //parameters that map to the resource, think `/dev/chardeviceXXX`
}
这些资源的数量是有限的,用户会随机同时请求访问它们,因此您将它们打包在管理器中
type ResourceManager struct{
Resources []*Resource //or a map
}
我正在尝试找出让经理创建一个函数func (m *ResourceManager)GetUnusedResouce()(*Resouce,error) 的最佳、安全方法,该函数将:
- 遍历所有资源,直到找到未使用的资源
- 将其标记为 InUse 并将 *Resouce 返回到调用上下文/goroutine
- 我会锁定以避免任何系统级锁定 (flock) 并在 Go 中完成这一切
- 还需要一个函数来标记资源不再使用
现在我在管理器中使用互斥锁来锁定访问,因为我遍历整个切片。它是安全的,但我希望能够通过同时搜索已使用的资源并处理两个尝试将同一资源标记为 InUse 的 goroutine 来加快速度。
更新
我特别想知道是否将资源InUse 字段设置为int64,然后使用atomic.CompareAndSwapInt64 将允许资源管理器在发现未使用的资源时正确锁定:
func (m *ResourceManager)GetUnusedResouce()(*Resouce,error){
for i := range Resources{
if atomic.CompareAndSwapInt64(&Resouces[i].InUse,1){
return Resouces[i],nil
}
}
return nil, errors.New("all resouces in use")
}
任何可以更好地测试这一点的单元测试也将不胜感激。
【问题讨论】:
-
您可能希望将正在使用的资源(可能由将用于释放的句柄标识)和空闲资源分开存储。
-
如果对管理器和资源的唯一访问是这里描述的,那么在管理器中保留一个受互斥锁保护的可用资源单链表。 GetUnusedResource 从列表中获取第一个资源。 ReleaseResource 将资源添加到列表的开头。
-
@CeriseLimón 这绝对是安全的做法,但对 Go 并发模型有更深入了解的人可能能够锁定 !InUse 检测,使用类似
atomic.CompareAndSwapInt -
我建议采用@cerise-limón 的建议:如果您需要其他人对原子操作是否有效的见解,您不需要原子操作 这一次: 作为一个程序员,你最关心的应该是让你的代码正确;一旦你对相关概念有了扎实的知识,你就可以让它更快(并且仍然正确)。
-
@kostix 问题已更新,以反映我希望看到更多技术和更快的选择,因为我已经有了一个安全的选择
标签: go concurrency