在函数结束之前,解锁已经延迟的读解锁RWMutex的最佳实践是什么?

huangapple go评论74阅读模式
英文:

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() // &lt;----
		return false, err
	}

	path := ref.ToPath(s.StructName)
	if (path == nil) {
		s.RUnlock() // &lt;----
		return false, nil
	}

	value, err := dbdrivers.DB.Get(path)
	if err != nil {
		s.RUnlock() // &lt;----
		return false, err
	}
	// Concurrent-dangerous stuff ends
	// RUnlock should technically be here
	s.RUnlock() // &lt;----

	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>



huangapple
  • 本文由 发表于 2021年12月6日 01:14:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/70236655.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定