引用计数
优点:
- 具有实时性,一旦变量没有被引用,就会把变量给释放掉
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。
使用规则
-
如果针对指针指向的内容创建了一个非临时的副本,然后将该副本通过指针传到另外的执行线程。在这种情况下,必须在传递指针之前,使用kref_get()增加引用计数。
-
在完成了对指针的操作之后,必须调用kref_put,使引用计数减一。如果计数值被减为0,这时需要调用释放函数,将申请的结构释放掉,
指向嵌有引用计数字段的变量的有效指针指的是该变量的引用计数不为0
- 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);
}
相关的优化