Fork Me
编写信号处理函数的注意事项-Reentrant
04 Nov 2014 - by @ssdr

信号处理和非可重入函数(Nonreentrant)

信号处理函数通常不会做很复杂的事情,一般也就是设置个经常使用的外部变量这样。当处理函数被多次调用的时候被操作的数据结构可能处于不连续的状态。即使是拷贝一个整形变量这样简单的操作在大多数机器上也是两条独立的指令。

小心信号处理函数

  1. 如果需要访问全局变量,将该变量声明为volatile
  2. 确定调用可重入函数,或者确定信号不会中断函数的执行。 ###如果使用不是栈上分配的内存,可能是非可重入的函数
  3. 函数使用静态数据、全局数据或动态分配对象,是不可重入的。如gethostbyname()返回静态数据。
  4. 函数使用或修改用户提供的对象,可能是不可重入的。使用stream的IO操作,如信号处理函数中使用fprintf输出信息。
  5. 在大多数系统中,mallocfree是不可重入的,因为他们使用静态数据结构记录空闲内存块。因此,任何分配和释放内存的库函数都是不可重入的,包括分配空间用于保持结果的函数。防止处理函数内部分配内存的方法是在信号处理函数外部提前分配好内存。防止在处理函数内部释放内存的方法是添加标记记录要释放的内存块,用专门的程序不时检查是否有需要释放的内存。不过这需要注意,因为将一个对象放入链表中不是原子性操作,如果被相同的信号处理函数中断,你可能失去该对象。
  6. 任何修改errno的函数都是不可重入的。解决方案:在信号处理函数中保存旧errno值,在返回前回复该值。另外,如果你想调用某函数,该函数会修改内存中分配的特定对象,可以通过保存并恢复该对象使该函数可重入。
  7. 当信号处理函数运行时,你可以一次处理对象中任何值,内存中的只读数据是安全的。请记住,有些数据类型的赋值操作不仅仅需要一条指令,也就是说信号处理函数可能在赋值操作中间被运行。
  8. 当信号处理函数运行时,如果值的修改不会disturb任何事,内存中的只写数据也是安全的。 ##线程安全和可重入的关系 一图胜前言

详细信息你看这里