在linux内核模块中printk的奇怪行为
我正在为linux内核模块编写代码,并且遇到了一个奇怪的行为。 这里是我的代码:在linux内核模块中printk的奇怪行为
int data = 0;
void threadfn1()
{
int j;
for(j = 0; j < 10; j++)
printk(KERN_INFO "I AM THREAD 1 %d\n",j);
data++;
}
void threadfn2()
{
int j;
for(j = 0; j < 10; j++)
printk(KERN_INFO "I AM THREAD 2 %d\n",j);
data++;
}
static int __init abc_init(void)
{
struct task_struct *t1 = kthread_run(threadfn1, NULL, "thread1");
struct task_struct *t2 = kthread_run(threadfn2, NULL, "thread2");
while(1)
{
printk("debug\n"); // runs ok
if(data >= 2)
{
kthread_stop(t1);
kthread_stop(t2);
break;
}
}
printk(KERN_INFO "HELLO WORLD\n");
}
基本上我试图等待线程完成,然后打印后的东西。 上述代码确实实现了该目标,但未注释WITH "printk("debug\n");"
。只要我注释掉printk("debug\n");
以在没有调试的情况下运行代码并通过insmod命令加载模块,模块就会挂起,看起来它在递归中会丢失。我不明白为什么printk会以这么大的方式影响我的代码?
任何帮助,将不胜感激。
关于。
由于删除了编译器优化循环到while (1);
调用printk()
。当您将呼叫添加到printk()
时,编译器不确定data
未更改,因此每次都通过循环检查值。
您可以在循环中插入一个障碍,这会强制编译器在每次迭代中重新评估data
。例如:
while (1) {
if (data >= 2) {
kthread_stop(t1);
kthread_stop(t2);
break;
}
barrier();
}
也许数据应该被声明为volatile?这可能是编译器不会去内存中获取循环中的数据。
您不同步对数据变量的访问。会发生什么是编译器会产生一个无限循环。原因如下:
while(1)
{
if(data >= 2)
{
kthread_stop(t1);
kthread_stop(t2);
break;
}
}
编译器可以检测到数据的值在while循环内永远不会改变。因此,它可以完全移动退房循环,你会用一个简单的
while (1) {}
最终如果你插入printk编译器必须假定全局变量的数据可能会改变(毕竟 - 编译器不知道具体做什么的printk),因此您的代码将再次开始工作(在不确定的行为的一种方式。)
如何解决这个问题:
使用正确的线程同步原语。如果将对数据的访问包装到由互斥锁保护的代码段中,代码将起作用。您也可以替换可变数据并使用计数的信号量。
编辑:
此链接介绍如何在Linux内核锁定的工作方式:
http://www.linuxgrill.com/anonymous/fire/netfilter/kernel-hacking-HOWTO-5.html
Nils Pipenbrinck的回答是现货。我只是添加一些指针。
Rusty's Unreliable Guide to Kernel Locking(每个内核黑客都应该读这个)。
Goodbye semaphores?,The mutex API(lwn.net关于新的互斥API的文章在2006年初推出,之前Linux内核使用信号量作为互斥体)。另外,由于您的共享数据是一个简单的计数器,因此您可以使用原子API(基本上,将计数器声明为atomic_t并使用atomic_ *函数访问它)。
挥发性可能并不总是“坏主意”。需要分离出当需要易失性时和需要互斥机制时的情况。当一个人使用或误用另一个机制时,它不是最佳的。在上述情况下。我建议 最佳的解决方案,这两个机制是必要的:互斥到 提供互斥,易失性向编译器表明 “信息”必须从硬件新鲜读取。否则,在某些 的情况下(优化-O2,-O3),编译器可能会在不经意间 遗漏所需的代码。
volatile会有些作用,但它总是一个坏主意,因为你不能确保data ++是一个原子指令。在多线程争取同一个变量的多处理器系统上,这会给你一个有保证的竞争条件。 – 2010-11-06 13:18:14
伟大的一点。这里不要使用volatile。需要更多的咖啡。 ;-) – 2010-11-06 13:22:29