女主宣言

一个不可重入的函数就是一个在任何时间点只能执行一次的函数,不管它被调用了多少次,以及有多少goroutines。

PS:丰富的一线技术、多元化的表现形式,尽在“HULK一线技术杂谈”,点关注哦!

一个不可重入的函数就是一个在任何时间点只能执行一次的函数,不管它被调用了多少次,以及有多少goroutines。

本篇文章说明了阻塞不可重入函数,并在golang中产生不可重入的函数实现。

场景用例

某个服务是对某些条件进行轮询,每秒监视一些状态。我们希望每个状态都可以独立地检查,而不需要阻塞。实现可能是这样的:

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

我们选择在自己的goroutine中运行每个状态检查,以便 CheckAnotherStatus() 不会等待 CheckSomeStatus() 完成。

每一项检查通常都要花费很短的时间,而且比一秒要少得多。但是,如果 CheckAnotherStatus() 本身需要超过一秒的时间运行,会发生什么呢?可能会有一个意外的网络或磁盘延迟影响检查的执行时间。

在同一时间执行两次的函数是否有意义?如果没有,我们希望它是不可重入的。

阻塞,不可重入函数

防止函数多次运行的简单方法是使用sync.Mutex。

假设我们只关心从上面的循环调用这个函数,我们可以从函数外面实现锁:

import ("sync""time"
)

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

上面的代码保证了 CheckAnotherStatus() 不是由循环的多次迭代执行的。在以前执行 CheckAnotherStatus() 的时候,循环的任何后续迭代都会被互斥锁阻塞。

阻塞解决方案具有以下属性:

  • 它确保了许多“CheckAnotherStatus()”的调用作为循环迭代的次数。

  • 假设一个执行“CheckAnotherStatus()”的停顿,随后的迭代会导致请求调用相同函数的请求。

屈服,不可重入函数

在我们的状态检查故事中,对随后的10个电话堆积起来可能没有意义。一个停滞不前的 CheckAnotherStatus() 执行完成了,所有10个调用突然执行,顺序,并且可能在接下来的一秒内完成,在同一秒内完成10个相同的检查。

另一个解决办法是屈服。一个有收益的解决方案是:

  • 如果已经执行了“CheckAnotherStatus()”的中止执行。

  • 将最多运行一次“CheckAnotherStatus()”的执行。

  • 与循环迭代的次数相比,实际上可能运行的“CheckAnotherStatus()”的调用更少。

解决方案是通过以下方式实现的:

import (    "sync/atomic""time")

func main() {tick := time.Tick(time.Second)    var reentranceFlag int64go 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) 只有在 reentranceFlag==0 时才会返回true,并将原子性地设置为1。在这种情况下,允许进入,并且可以执行该函数。reentranceFlag保持在1,直到 CheckAnotherStatus() 完成,此时它被重置。当 CompareAndSwapInt64(...) 返回false时,这意味着reentranceFlag!=0,这意味着该函数已经由另一个goroutine执行。代码产生并静默地退出函数。

总结

我们选择在问题的函数之外实现不可重入的代码;我们可以在函数本身中实现它。另外,对于 int64 而言,int32当然也足够用。以上就是本篇的内容,大家有什么疑问可以在文章下面留言沟通。

HULK一线技术杂谈

由360云平台团队打造的技术分享公众号,内容涉及云计算、数据库、大数据、监控、泛前端、自动化测试等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享

Golang之不可重入函数实现相关推荐

  1. 什么是可重入函数和不可重入函数

    可重入函数 在 实时系统的设计中,经常会出现多个任务调用同一个函数的情况.如果这个函数不幸被设计成为不可重入的函数的话,那么不同任务调用这个函数时可能修改其他任 务调用这个函数的数据,从而导致不可预料 ...

  2. 线程安全与可重入函数的区别及联系

    一.线程安全 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码.如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的.  或者 ...

  3. Linux中的可重入函数和不可重入函数

    可重入函数 可重入函数(即可以被中断的函数)可以被一个以上的任务调用,而不担心数据破坏.可重入函数在任何时候都可以被中断,而一段时间之后又可以恢复运行,而相应的数据不会破坏或者丢失. 可重入函数使用的 ...

  4. 可重入函数、不可重入函数,注意事项

    1.定义可重入函数,函数内不能含有全局变量及static变量,不能使用malloc.free 2.信号捕捉函数应设计为可重入函数 3.信号处理程序可以调用的可重入函数可参阅 man 7 signal ...

  5. 可重入函数与不可重入函数(转)

    转自:http://www.cppblog.com/franksunny/archive/2007/08/03/29269.html 主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数 ...

  6. 14.线程安全?线程不安全?可重入函数?不可重入函数?

    线程安全问题 基本定义 线程安全:简单来说线程安全就是多个线程并发执行同一段代码时,不会出现不同的结果,我们就可以说该线程是安全的: 线程不安全:如果多线程并发执行时会产生不同的结果,则该线程就是不安 ...

  7. UNIX再学习 -- 可重入函数和 SIGCHLD 语义

    一.可重入函数 参与信号处理的函数必须是可重入函数. 1.何为重入? 假设进程的住控制流程此刻正在调用 foo 函数,就在 foo 函数刚执行到一半的时候,内核向进程递送了信号 a:假设进程对信号 a ...

  8. 2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,

     1信号产生原因 2.进程处理信号行为 manpage里信号3中处理方式: SIG_IGN SIG_DFL                                            默 ...

  9. 【Linux系统编程】可重入和不可重入函数

    00. 目录 文章目录 00. 目录 01. 不可重入函数 02. 可重入函数 03. 判断条件 04. Linux常用可重入函数 05. 附录 01. 不可重入函数 在实时系统的设计中,经常会出现多 ...

最新文章

  1. c detail of macro
  2. 编译时异常和运行时异常的区别
  3. sublime配置攻略
  4. android手机如何安装apk文件,如何安装APK文件到自己的android手机里?.doc
  5. CF643F-Bears and Juice【组合数学】
  6. LeetCode 1353. 最多可以参加的会议数目(排序+贪心,优先队列,难)
  7. k8s 集群居然可以图形化安装了?
  8. python3-开发进阶补充Django中的文件的上传
  9. WEB消息提醒实现之二 实现方式-Jquery Ajax长轮询
  10. mpc 安全多方计算协议_HashKey:说透安全多方计算 MPC 技术方案、挑战与未来
  11. 潭州课堂25班:Ph201805201 tornado 项目 第八课 增加喜欢功能(课堂笔记)
  12. java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/Str
  13. 处置Linux下Oracle Tomcat 8080端口辩说
  14. std::sort使用
  15. idea 调节背景护眼_IDEA 护眼色设置 背景行颜色取消等设置
  16. 微信小程序:升级版手机检测微信工具小程序源码
  17. CiteSpace学习笔记(四)——功能区和参数区
  18. 如何从零开始学习软件测试
  19. 螺旋传动设计系统lisp_螺旋传动设计
  20. linux系统下查看cpu功耗,Linux系统下查看CPU信息

热门文章

  1. 美次债危机负面效应正扩大到消费市场
  2. Spark GraphX算法 - Aggregate Messages (aggregateMessages)算法
  3. 实现option上下移动_JS实现Select的option上下移动的方法
  4. java作业不能运行_从Windows运行时,YARN作业失败
  5. binlog日志_mysql的binlog日志的自动定时清理
  6. 大兴新年大集 推10条文化旅游线
  7. Asp.Net前台调用后台变量
  8. js处理倒计时,日期可以是当前日期也可以传1个时间点
  9. 《算法导论》读书笔记之第9章 中位数和顺序统计学
  10. Calypso - Android和Evolution下的CalDAV/CardDAV/Web...