1024programmer Java Golang tutorial: How to implement non-reentrant functions

Golang tutorial: How to implement non-reentrant functions

Function function

Go functions do not support nesting, overloading and default parameters

But the following features are supported:

  • No need to declare prototype
  • Indefinite length variable parameters
  • Multiple return values
  • Named return value parameters
  • Anonymous function
  • Closure

Foreword

A non-reentrant function is a function that can only be executed once at any point in time, regardless of how many times it is called and how many goroutines there are.

This article explains blocking non-reentrant functions and generating non-reentrant function implementations in golang.

Scenario use cases

A certain service polls for certain conditions and monitors some status every second. We want each state to be checked independently without blocking. The implementation may look like this:

 func main() {
  tick := time.Tick(time.Second)
  go func() {
  for range tick {
   go CheckSomeStatus()
   go CheckAnotherStatus()
  }
  }()
 }

We chose to run each status check in its own goroutine so that CheckAnotherStatus() does not wait for CheckSomeStatus() to complete.

Each check usually takes a short time, much less than a second. But what happens if CheckAnotherStatus() itself takes more than a second to run? There may be an unexpected network or disk delay that affects the check execution time.

Does it make sense to have a function executed twice at the same time? If not, we want it to be non-reentrant.

Blocking, non-reentrant function

A simple way to prevent a function from running multiple times is to use sync.Mutex.

Assuming we only care about calling this function from the loop above, we can implement the lock from outside the function:

 import (
  "sync"
  "time"
 )

 func main() {
  tick := time.Tick(time.Second)
  var mu sync.Mutex
  go func() {
  for range tick {
   go CheckSomeStatus()
   go func() {
   mu.Lock()
   defer mu.Unlock()
   CheckAnotherStatus()
   }()
  }
  }()
 }

The above code ensures that CheckAnotherStatus() is not executed by multiple iterations of the loop. In previous executions of CheckAnotherStatus(), any subsequent iterations of the loop would have been blocked by the mutex.

Blocking solutions have the following properties:

  • It ensures that there are as many calls to “CheckAnotherStatus()” as the number of loop iterations.
  • Assuming a stall executing “CheckAnotherStatus() “, subsequent iterations result in requests to call the same function.

Yield, non-reentrant function

In our status check story, it probably doesn’t make sense to stack up to the next 10 calls. A stalled CheckAnotherStatus() execution completes, and all 10 calls suddenly execute, sequentially, and may complete within the next second, completing 10 identical checks in the same second.

Another solution is to surrender. A profitable solution is:

  • Abort execution if “CheckAnotherStatus()” has been executed.
  • At most one execution of “CheckAnotherStatus()” will be run.
  • Fewer calls to CheckAnotherStatus() may actually be run than the number of loop iterations.

The solution is achieved by:

 import (
  "sync/atomic"
  "time"
 )

 func main() {
  tick := time.Tick(time.Second)
  var reentranceFlag int64
  go func() {
  for range tick {
   go CheckSomeStatus()
   go func() {
   if atomic.CompareAndSwapInt64(&reentranceFlag, 0, 1) {
    defer atomic.StoreInt64(&reentranceFlag, 0)
   } else {
    return
   }
   CheckAnotherStatus()
   }()
  }
  }()
 }

atomic.compareandswapint64(&reentranceFlag, 0, 1) Returns true only when reentranceFlag==0 and sets it to 1 atomically. In this case, entry is allowed and the function can be executed. reentranceFlag remains at 1 until CheckAnotherStatus() completes, at which time it is reset. When CompareAndSwapInt64(...) returns false, it means reentranceFlag!=0, which means that the function has already been executed by another goroutine. The code spawns and exits the function silently.

Summary

We chose to implement non-reentrant code outside of the function in question; we could have implemented it in the function itself. In addition, for int64, int32 is certainly sufficient. The above is the content of this article. If you have any questions, you can leave a message below the article.

Okay, that’s the entire content of this article. I hope that the content of this article has certain reference and learning value for everyone’s study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.

This article is from the internet and does not represent1024programmerPosition, please indicate the source when reprinting:https://www.1024programmer.com/784262

author: admin

Previous article
Next article

Leave a Reply

Your email address will not be published. Required fields are marked *

Contact Us

Contact us

181-3619-1160

Online consultation: QQ交谈

E-mail: [email protected]

Working hours: Monday to Friday, 9:00-17:30, holidays off

Follow wechat
Scan wechat and follow us

Scan wechat and follow us

Follow Weibo
Back to top
首页
微信
电话
搜索