使用sigprocmask实现锁定

时间:2010-05-18 00:48:52

标签: multithreading linux-kernel signals

我正在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);

除了这种感觉很冗长之外,这很好。有没有更好的方法来做到这一点?

3 个答案:

答案 0 :(得分:1)

您会发现signals.h中的sigemptyset()sigaddset()只是宏或内联函数,因此它们在代码中执行内联。只需在调用时使用堆栈变量即可。

但是,为什么不在代码的单线程启动部分执行此操作?我也怀疑对sigprocmask的函数调用是原子的。阻止信号并不意味着您的代码将不会中断。

顺便说一句,我不确定你是如何使用ualarm的,但是如果你第一次调用它时没有捕获或忽略SIGALARM,你可能会杀死你的进程。

答案 1 :(得分:1)

正如WhirlWind指出的那样,信号集功能非常轻巧,甚至可以实现为宏;你也可以只保留一个只包含SIGALRM的信号集并重复使用它。

无论如何,如果信号在sigaddset()sigemptyset()来电期间发生 - new_setold_set变量,它实际上并非重要是(可能)线程本地的,并且在sigprocmask()返回之后才会输入临界区。

答案 2 :(得分:0)

sigprocmask()是唯一进入内核级别并实际更改信号屏蔽状态的函数。其他函数只是在调用sigprocmask或将集合传递给另一个信号相关函数之前设置掩码的操作函数。