我正在为 Linux 内核模块编写代码,并遇到了奇怪的行为。 这是我的代码:
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");
}
基本上,我试图等待线程完成,然后再打印一些内容。
上面的代码确实实现了该目标,但没有注释 "printk("debug\n");"
。一旦我注释掉 printk("debug\n");
以在不调试的情况下运行代码并通过 insmod 命令加载模块,该模块就会挂起,并且似乎在递归中丢失了。我不明白为什么 printk 对我的代码影响这么大?
如有任何帮助,我们将不胜感激。
问候。
最佳答案
您没有同步对数据变量的访问。发生的情况是,编译器将生成无限循环。原因如下:
while( 1 )
{
if( data >= 2 )
{
kthread_stop(t1);
kthread_stop(t2);
break;
}
}
编译器可以检测到 data 的值在 while 循环内永远不会改变。因此,它可以完全将检查移出循环,您最终会得到一个简单的
while (1) {}
如果你插入 printk ,编译器必须假设全局变量数据可能会改变(毕竟 - 编译器不知道 printk 详细做什么),因此你的代码将再次开始工作(以一种未定义的行为方式) ..)
如何解决这个问题:
使用正确的线程同步原语。如果将对数据的访问包装到受互斥锁保护的代码部分中,则代码将起作用。您还可以替换变量数据并使用计数信号量。
编辑:
此链接解释了 Linux 内核中的锁定如何工作:
http://www.linuxgrill.com/anonymous/fire/netfilter/kernel-hacking-HOWTO-5.html
关于multithreading - Linux 内核模块中 printk 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4113176/