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

时间:2018-10-31 06:35:43

标签: 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

是否有正确的方法(特别是使用自旋锁,因为我觉得那是我犯错的地方)?任何帮助将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

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

作为一般说明,当您发现自己剪切+粘贴相同的函数时,仅通过几个变量将它们区分开,很可能您已经找到了单个更通用函数的参数的理想候选者。这不仅在眼睛上更容易(不易阅读和验证),而且更易于进行实验。将手动编辑应用于十几个位置会很快变旧...