gpt4 book ai didi

linux-kernel - 为什么这段代码会死锁?

转载 作者:行者123 更新时间:2023-12-05 08:00:36 24 4
gpt4 key购买 nike

我在可加载模块中创建了 2 个 Linux 内核线程,并将它们绑定(bind)到在双核 Android 设备上运行的独立 CPU 内核。运行这几次后,我注意到设备通过 HW 看门狗定时器重置重新启动。我一直在解决这个问题。可能导致死锁的原因是什么?

基本上,我需要做的是,确保两个线程在不同的内核上同时运行 do_something() 而没有任何人窃取 cpu 周期(即禁用中断)。我为此使用自旋锁和 volatile 变量。我还有一个信号量供父线程在子线程上等待。

#define CPU_COUNT 2

/* Globals */
spinlock_t lock;
struct semaphore sem;
volatile unsigned long count;

/* Thread util function for binding the thread to CPU*/
struct task_struct* thread_init(kthread_fn fn, void* data, int cpu)
{
struct task_struct *ts;

ts=kthread_create(fn, data, "per_cpu_thread");
kthread_bind(ts, cpu);
if (!IS_ERR(ts)) {
wake_up_process(ts);
}
else {
ERR("Failed to bind thread to CPU %d\n", cpu);
}
return ts;
}

/* Sync both threads */
void thread_sync()
{
spin_lock(&lock);
++count;
spin_unlock(&lock);

while (count != CPU_COUNT);
}

void do_something()
{
}

/* Child thread */
int per_cpu_thread_fn(void* data)
{
int i = 0;
unsigned long flags = 0;
int cpu = smp_processor_id();

DBG("per_cpu_thread entering (cpu:%d)...\n", cpu);

/* Disable local interrupts */
local_irq_save(flags);

/* sync threads */
thread_sync();

/* Do something */
do_something();

/* Enable interrupts */
local_irq_restore(flags);

/* Notify parent about exit */
up(&sem);
DBG("per_cpu_thread exiting (cpu:%d)...\n", cpu);
return value;
}

/* Main thread */
int main_thread()
{
int cpuB;
int cpu = smp_processor_id();
unsigned long flags = 0;

DBG("main thread running (cpu:%d)...\n", cpu);

/* Init globals*/
sema_init(&sem, 0);
spin_lock_init(&lock);
count = 0;

/* Launch child thread and bind to the other CPU core */
if (cpu == 0) cpuB = 1; else cpuB = 0;
thread_init(per_cpu_thread_fn, NULL, cpuB);

/* Disable local interrupts */
local_irq_save(flags);

/* thread sync */
thread_sync();

/* Do something here */
do_something();

/* Enable interrupts */
local_irq_restore(flags);

/* Wait for child to join */
DBG("main thread waiting for all child threads to finish ...\n");
down_interruptible(&sem);
}

最佳答案

我不确定,这是一个真正的原因,但您的代码包含一些严重的错误。

首先 while (count != CPU_COUNT);。除非读取是原子的,否则不得在未持有锁的情况下读取共享变量。使用 count 不能保证是。

您必须使用锁保护对count 的读取。您可以将 while 循环替换为以下内容:

unsigned long local_count;
do {
spin_lock(&lock);
local_count = count;
spin_unlock(&lock);
} while (local_count != CPU_COUNT);

或者,您可以使用原子类型。注意没有锁定

atomic_t count = ATOMIC_INIT(0);

...

void thread_sync() {
atomic_inc(&count);
while (atomic_read(&count) != CPU_COUNT);
}

第二个 中断问题。我想,你不明白你在做什么。

local_irq_save() 保存和禁用中断。然后,您再次使用 local_irq_disable() 禁用中断。完成一些工作后,您可以使用 local_irq_restore() 恢复之前的状态,并使用 local_irq_enable() 启用中断。这种启用是完全错误的。您启用中断,而不管它们之前的状态如何。

第三问题。如果主线程未绑定(bind)到 cpu,则不应使用 smp_processor_id() 除非您确定内核不会在您获得 cpu 编号后立即重新调度。最好使用 get_cpu(),它会禁用内核抢占,然后返回 cpu id。完成后,调用 put_cpu()

但是,当您调用 get_cpu() 时,这是创建和运行其他线程的错误。这就是为什么你应该设置主线程的亲和性。

第四local_irq_save()local_irq_restore() 宏采用变量,而不是指向 unsigned long 的指针。 (我有一个错误和一些警告传递指针。我想知道你是如何编译你的代码的)。删除引用

最终代码可在此处获得:http://pastebin.com/Ven6wqWf

关于linux-kernel - 为什么这段代码会死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18022958/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com