c-带有自旋锁的内核线程计数器

标签 c multithreading linux-kernel kernel kernel-module

我们被要求创建五个内核线程,它们将全局计数器一一递增。我是内核空间编程的新手,所以我很难做到这一点 - 特别是处理内核线程和使用自旋锁。

这是我的代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/slab.h>

MODULE_LICENSE("GPL");
static spinlock_t my_lock = __SPIN_LOCK_UNLOCKED();
static struct task_struct *t1;
static struct task_struct *t2;
static struct task_struct *t3;
static struct task_struct *t4;
static struct task_struct *t5;
static int o;

typedef struct __counter_t {
    int value;
    } counter_t;

void init (counter_t *c) {
    c->value = 0;
}

void increment (counter_t *c) {
    spin_trylock(&my_lock);
    c->value++;
    spin_unlock(&my_lock);
}

int get(counter_t *c) {
    int rc;
    spin_trylock(&my_lock);  
    rc = c->value;
    spin_unlock(&my_lock);
    return rc;
}

static int t1_f(void *unused)
{
            int i=0;
            struct __counter_t *ctr1=kmalloc(sizeof(struct __counter_t), GFP_KERNEL);
        init(ctr1);
        for(i=0; i<5000; i++)
        {
            increment(ctr1);
        }
        o = get(ctr1);
        printk(KERN_INFO "Counter: %d\n",o);
        kfree(ctr1);
        msleep(1000);
        return 0;
}

static int t2_f(void *unused)
{
        int j=0;
        struct __counter_t *ctr2=kmalloc(sizeof(struct __counter_t), GFP_KERNEL);
        init(ctr2);
        for(j=0; j<5000; j++)
        {
            increment(ctr2);
        }
        o = o + get(ctr2);
        printk(KERN_INFO "Counter: %d\n",o);
        kfree(ctr2);
        msleep(1000);
        return 0;
}

static int t3_f(void *unused)
{    
        int k=0;
        struct __counter_t *ctr3=kmalloc(sizeof(struct __counter_t), GFP_KERNEL);
        init(ctr3);
        for(k=0; k<5000; k++)
        {
            increment(ctr3);
        }
        o = o + get(ctr3);
        printk(KERN_INFO "Counter: %d\n",o);
        kfree(ctr3);
        msleep(1000);
        return 0;
}     

static int t4_f(void *unused)
{
        int l=0;
        struct __counter_t *ctr4=kmalloc(sizeof(struct __counter_t), GFP_KERNEL);
        init(ctr4);
        for(l=0; l<5000; l++)
        {
            increment(ctr4);
        }
        o = o + get(ctr4);
        printk(KERN_INFO "Counter: %d\n",o);
        kfree(ctr4);
        msleep(1000);
        return 0;
}     
static int t5_f(void *unused)
{
        int m=0;
        struct __counter_t *ctr5=kmalloc(sizeof(struct __counter_t), GFP_KERNEL);
        init(ctr5);
        for(m=0; m<5000; m++)
        {
            increment(ctr5);
        }
        o = o + get(ctr5);
        printk(KERN_INFO "Counter: %d\n",o);
        kfree(ctr5);
        msleep(1000);
        return 0;
} 

static int __init init_thread(void)
{
    int f=0;
    int h=0;
    printk(KERN_INFO "Thread Creating....\n");
    t1 = kthread_create(t1_f, NULL, "mythread1");
    t2 = kthread_create(t2_f, NULL, "mythread2");
    t3 = kthread_create(t3_f, NULL, "mythread3");
    t4 = kthread_create(t4_f, NULL, "mythread4");
    t5 = kthread_create(t5_f, NULL, "mythread5");
    if((((t1 && t2) && t3)&& t4)&&t5)
    {
    printk(KERN_INFO "Thread Created Successfully\n");
    while(!h) {
        if(f==0)
        {       
            spin_trylock(&my_lock);
            wake_up_process(t1);
            spin_unlock(&my_lock);
            f=1;
        }
        else if(f==1)
        {       
            spin_trylock(&my_lock);
            wake_up_process(t2);
            spin_unlock(&my_lock);
            f=2;
        }   
        else if(f==2)
        {
            spin_trylock(&my_lock);
            wake_up_process(t3);
            spin_unlock(&my_lock);
            f=3;
        }
        else if(f==3)
        {
            spin_trylock(&my_lock);
            wake_up_process(t4);
            spin_unlock(&my_lock);
            f=4;
        }
        else if(f==4)
        {
            spin_trylock(&my_lock);
            wake_up_process(t5);
            spin_unlock(&my_lock);
            h=1;
        }
    }
    }
    else
    {
        printk(KERN_ALERT "Thread Creation Failed\n");
    }
    return 0;
}

static void __exit cleanup_thread(void)
{   
    printk(KERN_INFO "Cleaning up.....\n");
}

module_init(init_thread);
module_exit(cleanup_thread);

结果应该是:

counter: 5000
counter: 10000
counter: 15000
counter: 20000
counter: 25000

但是我得到了不同的(错误)结果,例如:

counter: 5000
counter: 10000
counter: 5000
counter: 10000
counter: 15000

有没有正确的方法来做到这一点(特别是使用自旋锁,因为我觉得这就是我犯错误的地方)?任何帮助将不胜感激。谢谢!

最佳答案

什么是保护变量o;如 o = o + get(ctr{0..n})?查看您的代码,对于某些计数器(例如 ctr2),您使用自旋锁保护其更新,但是任何其他线程真的有可能访问该计数器吗?看起来它是线程本地的,所以并不需要保护;而‘o’是所有线程共享的,确实需要保护。

作为一般说明,当您发现自己剪切+粘贴相同的函数,只是通过几个变量来区分它们时,很可能您已经发现了单个更通用函数的参数的良好候选者。这既更方便眼睛(更少阅读和验证),也更适合实验。对十几个位置应用手动编辑很快就会过时......

关于c-带有自旋锁的内核线程计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53077614/

相关文章:

c - 内存读/写操作中的总线错误

c - 如何在 header 中构造函数,在源代码中定义

从摄氏度到华氏度的转换返回 0.00

java - 我怎样才能在这个任务中只运行一次任务

c++ - 栅栏实际上如何在 C++ 中工作

c - 在 C 中创建目录的线程安全函数

linux-kernel - 使用yocto进行内核选择

linux - QEMU 调试::警告:TCG 不支持请求的功能:CPUID.01H:ECX

c - 从字节数组中解压整数

c++ - 如何在c中实现一个类