繁体   English   中英

sig_atomic_t在Linux信号掩码功能中的用法

[英]The usage of sig_atomic_t in linux signal mask function

我最近正在学习一本名为《高级Linux编程》的书,并且遇到了这个问题:该书说您应该使用sig_atomic_t变量类型,以确保如果您在信号处理程序函数中设置了全局标志或计数器,则不会在之间进行上下文切换算术运算(即++ )并将其保存到寄存器中。

我的问题是:如果我们不使用sig_atomic_t而仅使用另一种类型并且发生上下文切换, sig_atomic_t发生什么? 我的意思是程序将只返回并保存,例如稍后。 有人可以给我一个方案,它会使我们的代码不稳定或有故障吗?

在您描述的场景中运行的风险(从内存读取到寄存器,更新寄存器,写入内存,并且在任何这些操作之间发生上下文切换)都是您可能会丢失在其他上下文中所做的更新。

例如:

main context:
  read i (=10) from memory to register R1
  add 5 to R1
    <interrupt. Switch to interrupt context>
    read i (=10) from memory to register R1
    add 10 to R1
    write R1 to i in memory (i = 20)
    <end of interrupt. Back to main context>
  write R1 to i in memory (i = 15)

如您所见,中断的更新已丢失。

如果您的类型需要多次操作才能将其写入内存,而中断发生在写操作的中间,则会出现更大的问题。

例如:

main context:
  read first half of i (=10) from memory to register R1
  read second half of i (=10) from memory to register R2
  add 5 to R1/R2 pair
  write R1 to first half of i in memory
    <interrupt. Switch to interrupt context>
    read first half of i (= ??) from memory to register R1
    read second half of i (= ??) from memory to register R2
    add 10 to R1/R2 pair
    write R1 to first half of i in memory
    write R2 to second half of i in memory
    <end of interrupt. Back to main context>
  write R2 to second half of i in memory

在这里,没有告诉我最终将获得什么价值。

使用sig_atomic_t ,不会发生第二个问题,因为可以保证类型使用原子读/写操作。

这是导致不安全行为的示例:

int64_t a = 2^32-1;

void some_signal_handler()
{
   ++a;
}

void f()
{
  if( a == 0 )
    printf("a is zero");
}

假设一个32位架构。 变量a实际上存储为2个32位整数,并以{0,2 ^ 32-1}开头。 首先f读取a的上半部分为0。然后出现信号,执行切换到信号处理程序。 它将a从2 ^ 32-1增加到2 ^ 32 a的新值为{1,0}。 信号处理程序完成,并且f的执行继续。 f读取a的下半部分为0。总共f读取a为零,这从没打算。

与从信号处理程序写入变量相比,更好的解决方案是保持管道打开,并从信号处理程序向管道写入值。 这样做的好处是它可以唤醒选择(只要您在管道的读取端进行选择),而不会出现任何竞争情况,并使您可以对主信号进行大部分主要处理。选择循环,您可以在其中随意使用所需的任何库函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM