英文:
What is the best practice to unlock an already-deferred read-unlock RWMutex before the end of the function?
问题
你想知道解决这个问题的最佳方法。
基本上,我想在函数中尽早解锁读取互斥锁,因为最后一部分是并发安全的。
如果我只是在底部部分(在"RUnlocked should technically be here"处)添加一个s.RUnlock
,同时保留延迟语句,如果我理解正确的话,这将导致问题。据我理解,RUnlock
通过计数器工作。因此,如果我的程序达到那个点之后("RUnlocked should technically be here"),它将在函数结束时调用s.RUnlock
和延迟的s.RUnlock
。因此,计数器将减少两次,可能会导致灾难。
因此,我能想到的唯一解决办法是这样的-这可能会在以后引发问题,因为我需要考虑函数可能结束的所有地方:
func (s *Structure) Get(key interface{}, object interface{}) (found bool, err error ){
s.RLock()
// Concurrent-dangerous stuff begins
ref, err := s.Index.GetOneEquals(string(s.StructName), key)
if err != nil {
s.RUnlock() // <----
return false, err
}
path := ref.ToPath(s.StructName)
if (path == nil) {
s.RUnlock() // <----
return false, nil
}
value, err := dbdrivers.DB.Get(path)
if err != nil {
s.RUnlock() // <----
return false, err
}
// Concurrent-dangerous stuff ends
// RUnlock should technically be here
s.RUnlock() // <----
err = encoding.Marshaler.Unmarshal(value, object)
if err != nil {
return false, err
}
}
有没有更安全的方法来做到这一点?
英文:
I'm working on a database and I want to know the best way to solve this issue.
Basically, I would like to unlock the read mutex earlier in the function because the last bit is concurrent safe.
func (s *Structure) Get(key interface{}, object interface{}) (found bool, err error ){
s.RLock()
defer s.RUnlock()
// Concurrent-dangerous stuff begins
ref, err := s.Index.GetOneEquals(string(s.StructName), key)
if err != nil {
return false, err
}
path := ref.ToPath(s.StructName)
if (path == nil) {
return false, nil
}
value, err := dbdrivers.DB.Get(path)
if err != nil {
return false, err
}
// Concurrent-dangerous stuff ends
// RUnlock should technically be here
err = encoding.Marshaler.Unmarshal(value, object)
if err != nil {
return false, err
}
}
If I just add an s.RUnlocked at the bottom part (where it says RUnlocked should technically be here) while keeping the deferred statement, if I understand correctly, it will cause issues. As I understand it, RUnlock works via a counter. So if my program reaches beyond that point ("RUnlocked should technically be here"), it will call the s.RUnlocked and also the deferred s.RUnlocked as well when the function ends. So the counter will decrement two times which might cause a disaster.
Therefore, the only solution I can think of is this - which is begging for gotchas down the line because I need to think of everywhere the function can end:
func (s *Structure) Get(key interface{}, object interface{}) (found bool, err error ){
s.RLock()
// Concurrent-dangerous stuff begins
ref, err := s.Index.GetOneEquals(string(s.StructName), key)
if err != nil {
s.RUnlock() // <----
return false, err
}
path := ref.ToPath(s.StructName)
if (path == nil) {
s.RUnlock() // <----
return false, nil
}
value, err := dbdrivers.DB.Get(path)
if err != nil {
s.RUnlock() // <----
return false, err
}
// Concurrent-dangerous stuff ends
// RUnlock should technically be here
s.RUnlock() // <----
err = encoding.Marshaler.Unmarshal(value, object)
if err != nil {
return false, err
}
}
Is there a safer way to do this?
答案1
得分: 1
你可以将内部代码块放入自己的函数中,仍然可以使用defer
关键字:
func (s *Structure) Get(key interface{}, object interface{}) (found bool, err error) {
s.RLock()
failed, found, err := func() {
defer s.RUnlock()
ref, err := s.Index.GetOneEquals(string(s.StructName), key)
if err != nil {
return true, false, err
}
// 进行其他操作
return false, found, nil
}()
if failed {
return found, err
}
// 继续函数执行,锁已解除
}
这样做可以确保在函数执行完毕后自动释放锁。
英文:
You can still use defer
if you put the inner block into its own function:
func (s *Structure) Get(key interface{}, object interface{}) (found bool, err error ){
s.RLock()
failed, found, err:= func() {
defer s.RUnlock()
ref, err := s.Index.GetOneEquals(string(s.StructName), key)
if err != nil {
return true, false, err
}
// Do stuff
return false, found, nil
}()
if failed {
return found, err
}
// continue function, lock is unlocked
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论