当前位置:C++技术网 > 资讯 > 什么是可重入函数与不可重入函数?可重入函数分析

什么是可重入函数与不可重入函数?可重入函数分析

更新时间:2015-06-26 00:05:08浏览次数:1+次

    函数我们都不陌生,学过任何一种编程语言,我们都会知道函数怎么回事。而函数的更为高效安全的使用,则不是简单学习语言所能掌握的。
    要了解可重入函数,我们先了解一下背景。
    函数是一段载入到内存的代码。函数的代码可长可短,执行时间长度也不确定。在多线程中,线程之间是可以进行切换的。函数是一段写好的代码,属于程序公有的代码段。一个进程中有多个线程,每一个线程都可以调用这段函数代码执行。而在多线程环境中,线程的切换是无法预料的,你不知道下一秒是哪个线程在执行,每时每刻的运行环境都不一样,因为线程切换也是变化莫测的。这是操作系统调度进程线程的范围,不是我们能够掌控的。既然我们无法改变进程调度,无法得知线程切换的规律,那就不要依赖线程的切换。我们的程序要做到,无论线程怎么切换,执行的结果都要一致。
    那么如何做到函数执行的结果每次都一致呢?因为在多线程环境中,随时都可能被切换到其他线程执行。因为函数又是进程公共的代码段,因此,另外的线程也可以调用刚才的函数代码执行。当然,这次执行的函数和上次执行的函数完全无关。在此,或许你大概知道什么是重入的概念了。所谓的重入,就是同一段代码被重叠多次执行。上面的例子,第一次执行的函数还没有执行完,线程切换后,又被新线程执行了。两次执行会有问题吗?或者说,两次执行会相互影响吗?This is a question?! 
    我们再来看一个例子。如果你写一个递归函数,你会怎么写?递归函数是一个单线程的概念。因为CPU的执行,始终在一个线程中。函数执行只是不停的调用自己而已,并没有被切换到其他线程。但是调用一次自己,就带来了隐患。每次调用自己返回后,执行的结果还会保证不出错吗?因为是同一个函数,每次调用也会执行同样的代码,自己操作的变量,递归调用自己后还会执行,会不会导致变量值变得不可预测呢?答案是会滴。如何来做到正确使用递归函数呢?
    从上面两个例子,第一个是多线程的例子,第二个是单线程递归的例子,都可以看出,同一个函数被多次重叠执行,都会产生执行结果不一致的可能。上面的例子没有举出具体的例子来证明会产生不一致,但是事实,都是可能的。
    而我们要讨论的可重入函数就是针对这两个问题而产生的。正如上面所说,可重入函数的提出并不是针对多线程而言的,因为单线程也是会出现的。我们再提升一下思维,或许得出的结果更有普遍性。
    一个函数在执行的过程中被打断,然后会再被再重头执行一次,执行完后,再回来把刚才没执行完的部分执行完。这就相当于嵌套的执行了。函数是公共代码,这样的执行是允许的。函数的执行可以被打断,打断之后还可以再重头执行,执行完后接着执行刚才没有执行的代码,然后第一次执行的代码(被打断的函数)执行结果还是正确的。也就是说,这个函数执行,无论中间把这个函数再嵌入执行多少遍,怎么嵌入,最终执行完,执行的结果都是正确的,这样的函数就是可重入函数。
    很多资料都说这种函数主要用于多任务即多进程多线程环境中。其实在单线程的递归调用也是存在的。因为递归也满足这种“中断+嵌入执行自己+继续执行中断前代码”的特性。因此也构成了需要使用可重入函数的要求。
    以上说的就是想让你对可重入形成一个概念。可重入的概念只针对于函数本身的设计,与多线程单线程无关。我们所写的函数,都应该满足可重入函数的特性,这样让代码更可靠。而不可重入函数则是被中断嵌套执行后,之前执行的函数或者说被嵌套执行的函数的结构都不正确或者一些不正确了。这样的结果不是我们想要的。因为函数重叠执行,会导致每一层的函数相互影响,结果都不对。这样的函数是不安全的。我们要避免这个情况的发生。因此可重入函数就是必须重视的了。只要做到函数被嵌套后,每一层函数执行的结果都能正确,那就是可重入函数了。
    如何写出可重入函数,提高代码质量呢?了解了以上的概念,相信也不难找出答案。函数被多次重叠执行,只要每次执行的函数操作的变量不是公共的,或者说能够互斥的操作公共的变量,都是可以保证函数的可重入,保证结果的正确性。
    不使用或者互斥使用全局变量,不使用静态局部变量,只是用局部变量,在函数中动态分配的内存只在本函数中使用,不会传递函数外使用,只要保证局部特性,函数中使用的所有东西都只有局部性,对外不公开,用完即释放,就可以保证可重入。这样,不管怎么重叠,反正本层的函数的东西只有本层能够使用,其他层的函数无法使用,就相当于隔离每一层的变量。这样,不管重叠多少次,都不可能相互影响。这样每一层函数执行的结果都是正确的。
    但是要特别注意,单线程递归调用时,使用全局变量不好做到可重入。因为每一层函数都会操作全局变量。但是如果对全局变量加锁,上一层使用后,调用下一层的自己,结果全局变量被锁上了,然后就一直等,就形成了死锁。这是很严重的问题。如果用不好,最好不要用,除非你很清楚你自己的代码流程。
    不知道文中把这个概念跟你讲清楚没有,可能有点啰嗦,但是是想不断的解释,让你理解的更到位。如果有不正确的地方,请指正。如果还有疑问,可以留言提问,我会尽快回复。