工作队列

       工作队列是一个用于创建内核线程的接口。通过他创建的进程负责执行由内核其他部分排到队列里的任务。工作队列的最基本的形式,就是把需要推后执行的任务交给特定的通用线程的这样一种接口。

       缺省的工作线程叫做event/n,n代表处理器的编号。缺省线程会从多个地方得到被推后的工作。

       工作这线程用workqueue_struct来表示。

Struct workqueue_struct {

       Structcpu_workqueue_struct cpu_wq[NR_CPUS];

       Structlist_head list;

       Constchar *name;

       Intsinqlethread;

       Intfreezeable;

       Intrt;

}

 

Cpu_workqueue_struct是kernel/workqueue.c当中的核心数据结构。

 

Struct cpu_workqueue_struct{

       Spinlock_tlock;     //锁保护这种结构

      

       Structlist_head worklist; // 工作列表

       Wait_queue_head_tmore_work;

       Structwork_struct *current_struct;

      

Structworkqueue_struct *wq;

Task_t *thread;

}

 

表示工作的数据结构

       所有的工作者线程都是由普通线程实现的。他们都要执行work_thread()函数,在他执行完初始化函数以后,这个函数就开始执行一个死循环并且开始休眠。当有操作被插入到队列里的时候,线程就会被唤醒。

       工作用linux/workqueue.h中定义的work_struct结构体表示

Struct work_struct{

       Atomic_long_tdata;

       Structlist_head entry;

       Work_func_tfunc;

}

这些结构体被连成链表。

Worker_thread()函数的核心流程。

For( ; ; )

{

       Prepare_to_wait(&cwq_morework,&more_work,&wait,TASK_INTERRUPTIBLE);

       If(list_empty(&cwq->worklist))

              Schedule();

       Finish_wait(&cwq->more_work,&wait);

       Run_workqueue(cwq); 

}

该函数完成了一下的功能:

       线程将自己设置成休眠状态(state被设置成TASK_INTERRUPTABLE),并把自己加到等待列队中

       如果工作链表是空的,线程调用schedule()函数进入休眠状态。

       如果链表当中有对象,线程不会睡眠。他会将自己设置成TASK_RUNNING,脱离等待队列。

       如果链表飞控,调用run_workqueue()函数完成推后的工作。

While(!list_empty(&cwq->worklist)) {

       Structwork_struct *work;

       Work_func_tf;

       Void*data;

      

       Work= list_entry(cwq->worklist.next, struct work_struct,entry );

       F= work.func;

       List_del_init(cwq->worklist.next);

       Work_clear_pending(work);

       f(work);

}

       当链表不为空的时候,选取下一个节点对象

       获取我们希望执行的函数func以及参数data

       把该节点从链表上解下来,将待处理标志位pending清零。

       调用函数

重复执行

使用工作队列

       首先看一下默认的events任务队列,

1、 创建退后的工作:

首先要做的是实际创建一些需要推后完成的额工作,可以通过DECLEAR_EORK在编译时静态创建该结构体。

DECLEAR_WORK(struct work_struct *work,void (*func) (void*).void*data);

              同样也可以在运行时通过指针创建一个工作。

              INIT_WORK(structwork_struct *work,void (*func) (void*).void *data);

 

2、 工作队列处理函数

void work_handler(void *data)

3、 对工作进行调度

想要把给定工作的处理函数提交给默认的工作现成,需要调用:

Schedule_work(&work);

如果需要一定的延时,可以使用:

Schedule_delayed_work(&work,delay);

4、 刷新操作

有时,在进行下一步的操作之前,必须保证一些操作已经完成,为了防止竞争条件的出现,也需要确保不再有待处理的工作。

        因此内核准备了一个用于刷新制定队列的函数:

        void flush_scheduled_work(void);

如果需要取消延迟执行的工作应该调用

int cancel_delayed_work(struct work_struct *work)

5、 创建新的工作队列

创建一个新的任务列队和与之相关的工作者线程,需要调用一个函数

Sstructworkqueue_struct *creat_workqueue(const char *name);

 

Name参数用于内核现成的命名,比如,默认的events队列的创建就是调用:

Struct_workqueue_struct*keventd_wq;

Kevents_wq =creat_workqueue(*events);

 

创建一个工作的时候无需考虑工作队列的类型,使用到的函数有,

Int queue_work (structworkqueue_struct *wq,struct work_struct *work)

 

Int queue_delayed_work(tructworkqueue_struct *wq,struct work_struct *work,unsigned long delay);

 

最后可以调用制定的函数刷新制定的工作队列。

 

flush_orkqueue(structworkqueue_struct *wq);

 

老的任务队列机制

       下半部分机制的选择:

       下下半部分的实现在2.6内核当中有三种实现的方式:软中断,tasklet和工作队列。

软中断提供的执行序列化的保障最少。这样就必须格外小心的采取一些步骤确保共享数据的安全。

       一般的驱动程序编写者需要做两个选择。首先是不是需要一个可调度的实体来执行需要退后的工作。

在下半部之间加锁

       枷锁问题是一个有趣且广泛的话题。

 

今天就这样了

 

爱你 YZ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值