linux内核中实现的引用计数机制——kref

引用计数

优点:

  1. 具有实时性,一旦变量没有被引用,就会把变量给释放掉

kref机制:是linux内核中使用的引用计数机制,

下面介绍一下,在内核中该如何使用引用计数这个技术,首先,在设计自己的数据结构时,要包含struct kref结构的字段。

数据结构和初始化

typedef struct {
    int counter;
} atomic_t;

typedef struct refcount_struct {
    atomic_t refs;
} refcount_t

struct kref {
    refcount_t refcount;
};

使用示例:

struct my_data
{
    ...
    struct kref refcount;
    ...
};

初始化的示例代码:

struct my_data *data;

data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
    return -ENOMEM;
kref_init(&data->refcount);

上面的代码会将data变量的引用计数设置为1。

使用规则

  1. 如果针对指针指向的内容创建了一个非临时的副本,然后将该副本通过指针传到另外的执行线程。在这种情况下,必须在传递指针之前,使用kref_get()增加引用计数。

  2. 在完成了对指针的操作之后,必须调用kref_put,使引用计数减一。如果计数值被减为0,这时需要调用释放函数,将申请的结构释放掉,

指向嵌有引用计数字段的变量的有效指针指的是该变量的引用计数不为0

  1. If the code attempts to gain a reference to a kref-ed structure without already holding a valid pointer, it must serialize access where a kref_put() cannot occur during the kref_get(), and the structure must remain valid during the kref_get(). 我理解的意思就是如果线程在还未获得有效指针的时候去获取对相应结构变量的引用,所以在kref_get调用之后访问处理的过程中不能出现kref_put,不能断断续续的访问。

例子

我们分配一个my_data类型的变量,然后把这个变量传入其他线程去执行

void data_release(struct kref *ref)
{
    struct my_data *data = container_of(ref, struct my_data, refcount);
    kfree(data);
}

/* 对于 */
void more_data_handling(void *cb_data)
{
    struct my_data *data = cb_data;
    /*
    * do stuff with data here
    */
    /*  */
    kref_put(&data->refcount, data_release);
}

/* 主线程 */
int my_data_handler(void)
{
    int rv = 0;
    struct my_data *data;
    struct task_struct *task;
    /* 分配数据结构 */
    data = kmalloc(sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;
    /* 初始化引用计数 */
    kref_init(&data->refcount);

    /* 在传入其他线程之前对引用计数加一,表示有多的一个线程在使用该数据 */
    kref_get(&data->refcount);
    task = kthread_run(more_data_handling, data, "more_data_handling");
    if (task == ERR_PTR(-ENOMEM)) {
        rv = -ENOMEM;
        kref_put(&data->refcount, data_release);
        goto out;
    }

    /*
    * do stuff with data here
    */
out:
    /* 在这里没有调用kfree,去释放my_data这个数据结构 */
    kref_put(&data->refcount, data_release);
    return rv;
}

关于规则3,还有个例子:

我们有的数据结构是下面这样的,是一个链表,链表上的每个元素都有引用计数。

我们的需求是希望能获取链表中的第一个元素,将该元素提供给其他的线程使用。

我们不能只获取第一个元素,然后调用ref_get。如果要实现这个目标,我们需要对kef_get的操作加锁

static DEFINE_MUTEX(mutex);
static LIST_HEAD(q);
struct my_data
{
    struct kref      refcount;
    struct list_head link;
};

/*  */
static struct my_data *get_entry()
{
    struct my_data *entry = NULL;
    mutex_lock(&mutex);
    if (!list_empty(&q)) {
        entry = container_of(q.next, struct my_data, link);
        kref_get(&entry->refcount);
    }
    mutex_unlock(&mutex);
    return entry;
}

static void release_entry(struct kref *ref)
{
    struct my_data *entry = container_of(ref, struct my_data, refcount);

    list_del(&entry->link);
    kfree(entry);
}

static void put_entry(struct my_data *entry)
{
    mutex_lock(&mutex);
    kref_put(&entry->refcount, release_entry);
    mutex_unlock(&mutex);
}

相关的优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值