定义在头文件linux/irqflags.h中;
在单CPU内部避免竞态的一种方法是在进入临界区之前先屏蔽系统的中断,离开临界区之前再恢复系统中断;CPU一般都应该具有打开中断和关闭中断的功能;这项功能可以保证正在执行的内核代码执行路径不会被中断处理程序所抢占,防止某些竞态条件的发生;具体而言,中断屏蔽将使得中断与进程之间的并发不再出现,而且,由于Linux内核的进程调度等操作都是依赖中断来实现的,内核抢占进程之间的并发也就得以避免了;
中断屏蔽的使用方法:
local_irq_disable(); //关中断
....
cirtical section //临界区
....
local_irq_enable(); //开中断
Linux系统的异步IO、进程调度等重要操作都是依赖于中断来实现的,中断对于内核的运行来说非常重要,在屏蔽中断期间,所有的中断都无法得到处理,因此长时间屏蔽中断是非常危险的,有可能会造成数据丢失,甚至是系统崩溃;这就要求在屏蔽中断之后,当前的内核执行路径应当尽快地执行完临界区代码;
local_irq_disable()和local_irq_enable()是禁止和使能本CPU内部的中断,所以,屏蔽中断是不能解决SMP的多个CPU之间的竞态条件的;因此,单独使用屏蔽中断并不是一个值得推荐的避免竞态条件的方法,它应该适当滴与自旋锁联合使用;
local_irq_save(flags)除了屏蔽中断之外,还能保存当前CPU的中断位信息;local_irq_restore(flags)用于打开中断,并恢复当前CPU的中断位信息;
如果只是想屏蔽中断的低半部,应该使用local_bh_disable(),打开低半部的中断屏蔽时应使用local_bh_enable();
例子:
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/delay.h>
//这三个头文件与内核线程的使用有关;
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/err.h>
//中断屏蔽相关
#include <linux/irqflags.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("*************");
MODULE_VERSION("2.6.35.000");
static int sleep_time = (1*10*HZ);
static int iSharedRes = 0;
static int thread_process1(void* param)
{
unsigned long flags = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
local_irq_disable();
//local_irq_save(flags);
iSharedRes++;
printk("%s: shared resource = %d, flags=%lu;\n%s", __FUNCTION__, iSharedRes, flags, ((iSharedRes % 3) ? "" : "\n"));
local_irq_enable();
//local_irq_restore(flags);
mdelay(sleep_time);
}
return 123;
};
static int thread_process2(void* param)
{
unsigned long flags = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
local_irq_disable();
//local_irq_save(flags);
iSharedRes++;
printk("%s: shared resource = %d, flags=%lu;\n%s", __FUNCTION__, iSharedRes, flags, ((iSharedRes % 3) ? "" : "\n"));
local_irq_enable();
//local_irq_restore(flags);
msleep(sleep_time);
}
return 456;
};
static int thread_process3(void* param)
{
unsigned long flags = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if(kthread_should_stop())
{
printk("kernel thread '%s' should stop;file:%s;line:%d\n", __FUNCTION__, __FILE__, __LINE__);
break;
}
local_irq_disable();
//local_irq_save(flags);
iSharedRes++;
printk("%s: shared resource = %d, flags=%lu;\n%s", __FUNCTION__, iSharedRes, flags, ((iSharedRes % 3) ? "" : "\n"));
local_irq_enable();
//local_irq_restore(flags);
msleep(sleep_time);
}
return 789;
};
static struct task_struct* my_thread1 = NULL;
static struct task_struct* my_thread2 = NULL;
static struct task_struct* my_thread3 = NULL;
static int __init study_init(void)
{
int err = 0;
printk("%s\n", __PRETTY_FUNCTION__);
my_thread1 = kthread_create(thread_process1, NULL, "my_thread1");
if(IS_ERR(my_thread1))
{
err = PTR_ERR(my_thread1);
my_thread1 = NULL;
printk(KERN_ERR "unable to start kernel thread1:%d\n", err);
return err;
}
my_thread2 = kthread_create(thread_process2, NULL, "my_thread2");
if(IS_ERR(my_thread2))
{
err = PTR_ERR(my_thread2);
my_thread2 = NULL;
printk(KERN_ERR "unable to start kernel thread2:%d\n", err);
return err;
}
my_thread3 = kthread_create(thread_process3, NULL, "my_thread3");
if(IS_ERR(my_thread3))
{
err = PTR_ERR(my_thread3);
my_thread3 = NULL;
printk(KERN_ERR "unable to start kernel thread3:%d\n", err);
return err;
}
wake_up_process(my_thread1);
wake_up_process(my_thread2);
wake_up_process(my_thread3);
printk("%s:all kernel thread start;\n", __FUNCTION__);
return 0;
}
static void __exit study_exit(void)
{
int ret = -1;
printk("%s\n",__PRETTY_FUNCTION__);
if(my_thread1)
{
ret = kthread_stop(my_thread1);
my_thread1 = NULL;
printk("kernel thread1 stop,exit code is %d;\n",ret);
}
if(my_thread2)
{
ret = kthread_stop(my_thread2);
my_thread2 = NULL;
printk("kernel thread2 stop,exit code is %d;\n",ret);
}
if(my_thread3)
{
ret = kthread_stop(my_thread3);
my_thread3 = NULL;
printk("kernel thread3 stop,exit code is %d;\n",ret);
}
printk("%s:all kernel thread stop;\n", __FUNCTION__);
}
module_init(study_init);
module_exit(study_exit);