我正在Linux内核2.4中实现用户线程,我正在使用ualarm来调用线程之间的上下文切换。
我们要求我们的线程库的函数不应该被线程的上下文切换机制中断,所以我研究了阻塞信号,并了解到使用sigprocmask是执行此操作的标准方法。
然而,看起来我需要做很多工作才能实现这个目标:
sigset_t new_set, old_set;
sigemptyset(&new_set);
sigaddset(&new_set, SIGALRM);
sigprocmask(SIG_BLOCK, &new_set, &old_set);
这会阻止SIGALARM,但它会通过3次函数调用来执行此操作!在这些功能运行所需的时间内可能会发生很多事情,包括发送的信号。 我必须缓解的最好的想法是暂时禁用ualarm,如下所示:
sigset_t new_set, old_set;
time=ualarm(0,0);
sigemptyset(&new_set);
sigaddset(&new_set, SIGALRM);
sigprocmask(SIG_BLOCK, &new_set, &old_set);
ualarm(time, 0);
除了这种感觉很冗长之外,这很好。有没有更好的方法来做到这一点?
答案 0 :(得分:1)
您会发现signals.h中的sigemptyset()
和sigaddset()
只是宏或内联函数,因此它们在代码中执行内联。只需在调用时使用堆栈变量即可。
但是,为什么不在代码的单线程启动部分执行此操作?我也怀疑对sigprocmask的函数调用是原子的。阻止信号并不意味着您的代码将不会中断。
顺便说一句,我不确定你是如何使用ualarm的,但是如果你第一次调用它时没有捕获或忽略SIGALARM,你可能会杀死你的进程。
答案 1 :(得分:1)
正如WhirlWind指出的那样,信号集功能非常轻巧,甚至可以实现为宏;你也可以只保留一个只包含SIGALRM
的信号集并重复使用它。
无论如何,如果信号在sigaddset()
或sigemptyset()
来电期间发生 - new_set
和old_set
变量,它实际上并非重要是(可能)线程本地的,并且在sigprocmask()
返回之后才会输入临界区。
答案 2 :(得分:0)
sigprocmask()是唯一进入内核级别并实际更改信号屏蔽状态的函数。其他函数只是在调用sigprocmask或将集合传递给另一个信号相关函数之前设置掩码的操作函数。