精华内容
下载资源
问答
  • linux 延时工作队列

    千次阅读 2013-04-11 10:51:35
    localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ps -el F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD 4 S 0 1 0 0 76 0 - 195 - ? 00:00:02 init 1 S 0 2 1 0 -40 ...

    INIT_DELAYED_WORK()是一个宏,我们给它传递了两个参数.&hub->ledsled_work.对设备驱动熟悉的人不会觉得INIT_DELAYED_WORK()很陌生,其实鸦片战争那会儿就有这个宏了,只不过从2.6.20的内核开始这个宏做了改变,原来这个宏是三个参数,后来改成了两个参数,所以经常在网上看见一些同志抱怨说最近某个模块编译失败了,说什么make的时候遇见这么一个错误:

    error: macro "INIT_DELAYED_WORK" passed 3 arguments, but takes just 2

    当然更为普遍的看到下面这个错误:

    error: macro "INIT_WORK" passed 3 arguments, but takes just 2

    于是就让我们来仔细看看INIT_WORKINIT_DELAYED_WORK.其实前者是后者的一个特例,它们涉及到的就是传说中的工作队列.这两个宏都定义于include/linux/workqueue.h:

         79 #define INIT_WORK(_work, _func)                                         /

         80         do {                                                            /

         81                 (_work)->data = (atomic_long_t) WORK_DATA_INIT();       /

         82                 INIT_LIST_HEAD(&(_work)->entry);                        /

         83                 PREPARE_WORK((_work), (_func));                         /

         84         } while (0)

         85

         86 #define INIT_DELAYED_WORK(_work, _func)                         /

         87         do {                                                    /

         88                 INIT_WORK(&(_work)->work, (_func));             /

         89                 init_timer(&(_work)->timer);                    /

         90         } while (0)

    有时候特怀念谭浩强那本书里的那些例子程序,因为那些程序都特简单,不像现在看到的这些,动不动就是些复杂的函数复杂的数据结构复杂的宏,严重挫伤了我这样的有志青年的自信心.就比如眼下这几个宏吧,宏里边还是宏,一个套一个,不是说看不懂,因为要看懂也不难,一层一层展开,只不过确实没必要非得都看懂,现在这样一种朦胧美也许更美,有那功夫把这些都展开我还不如去认认真真学习三个代表呢.总之,关于工作队列,就这么说吧,Linux内核实现了一个内核线程,直观一点,ps命令看一下您的进程,

    localhost:/usr/src/linux-2.6.22.1/drivers/usb/core # ps -el

    F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

    4 S     0     1     0  0  76   0 -   195 -      ?        00:00:02 init

    1 S     0     2     1  0 -40   - -     0 migrat ?        00:00:00 migration/0

    1 S     0     3     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/0

    1 S     0     4     1  0 -40   - -     0 migrat ?        00:00:00 migration/1

    1 S     0     5     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/1

    1 S     0     6     1  0 -40   - -     0 migrat ?        00:00:00 migration/2

    1 S     0     7     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/2

    1 S     0     8     1  0 -40   - -     0 migrat ?        00:00:00 migration/3

    1 S     0     9     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/3

    1 S     0    10     1  0 -40   - -     0 migrat ?        00:00:00 migration/4

    1 S     0    11     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/4

    1 S     0    12     1  0 -40   - -     0 migrat ?        00:00:00 migration/5

    1 S     0    13     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/5

    1 S     0    14     1  0 -40   - -     0 migrat ?        00:00:00 migration/6

    1 S     0    15     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/6

    1 S     0    16     1  0 -40   - -     0 migrat ?        00:00:00 migration/7

    1 S     0    17     1  0  94  19 -     0 ksofti ?        00:00:00 ksoftirqd/7

    5 S     0    18     1  0  70  -5 -     0 worker ?        00:00:00 events/0

    1 S     0    19     1  0  70  -5 -     0 worker ?        00:00:00 events/1

    5 S     0    20     1  0  70  -5 -     0 worker ?        00:00:00 events/2

    5 S     0    21     1  0  70  -5 -     0 worker ?        00:00:00 events/3

    5 S     0    22     1  0  70  -5 -     0 worker ?        00:00:00 events/4

    1 S     0    23     1  0  70  -5 -     0 worker ?        00:00:00 events/5

    5 S     0    24     1  0  70  -5 -     0 worker ?        00:00:00 events/6

    5 S     0    25     1  0  70  -5 -     0 worker ?        00:00:00 events/7

    瞅见最后这几行了吗,events/0events/7,07啊这些都是处理器的编号,每个处理器对应其中的一个线程.要是您的计算机只有一个处理器,那么您只能看到一个这样的线程,events/0,您要是双处理器那您就会看到多出一个events/1的线程.哥们儿这里Dell PowerEdge 2950的机器,8个处理器,所以就是events/0events/7.

    那么究竟这些events代表什么意思呢?或者说它们具体干嘛用的?events被叫做工作者线程,或者说worker threads,更确切的说,这些应该是缺省的工作者线程.而与工作者线程相关的一个概念就是工作队列,或者叫work queue.工作队列的作用就是把工作推后,交由一个内核线程去执行,更直接的说就是如果您写了一个函数,而您现在不想马上执行它,您想在将来某个时刻去执行它,那您用工作队列准没错.您大概会想到中断也是这样,提供一个中断服务函数,在发生中断的时候去执行,没错,和中断相比,工作队列最大的好处就是可以调度可以睡眠,灵活性更好.

    就比如这里,如果我们将来某个时刻希望能够调用led_work()这么一个我们自己写的函数,那么我们所要做的就是利用工作队列.如何利用呢?第一步就是使用INIT_WORK()或者INIT_DELAYED_WORK()来初始化这么一个工作,或者叫任务,初始化了之后,将来如果咱们希望调用这个led_work()函数,那么咱们只要用一句schedule_work()或者schedule_delayed_work()就可以了,特别的,咱们这里使用的是INIT_DELAYED_WORK(),那么之后我们就会调用schedule_delayed_work(),这俩是一对.它表示,您希望经过一段延时然后再执行某个函数,所以,咱们今后会见到schedule_delayed_work()这个函数的,而它所需要的参数,一个就是咱们这里的&hub->leds,另一个就是具体自己需要的延时.&hub->leds是什么呢?struct usb_hub中的成员,struct delayed_work leds,专门用于延时工作的,再看struct delayed_work,这个结构体定义于include/linux/workqueue.h:

         35 struct delayed_work {

         36         struct work_struct work;

         37         struct timer_list timer;

         38 };

    其实就是一个struct work_struct和一个timer_list,前者是为了往工作队列里加入自己的工作,后者是为了能够实现延时执行,咱们把话说得更明白一点,您看那些events线程,它们对应一个结构体,struct workqueue_struct,也就是说它们维护着一个队列,完了您要是想利用工作队列这么一个机制呢,您可以自己创建一个队列,也可以直接使用events对应的这个队列,对于大多数情况来说,都是选择了events对应的这个队列,也就是说大家都共用这么一个队列,么用呢?先初始化,比如调用INIT_DELAYED_WORK(),这么一初始化吧,实际上就是为一个struct work_struct结构体绑定一个函数,就比如咱们这里的两个参数,&hub->ledsled_work()的关系,就最终让hub_leds这个struct work_struct结构体和函数led_work()相绑定了起来,您问怎么绑定的?您瞧,struct work_struct也是定义于include/linux/workqueue.h:

         24 struct work_struct {

         25         atomic_long_t data;

         26 #define WORK_STRUCT_PENDING 0          

         27 #define WORK_STRUCT_FLAG_MASK (3UL)

         28 #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)

         29         struct list_head entry;

         30         work_func_t func;

         31 };

    瞅见最后这个成员func了吗,初始化的目的就是让func指向led_work(),这就是绑定,所以以后咱们调用schedule_delayed_work()的时候,咱们只要传递struct work_struct的结构体参数即可,不用再每次都把led_work()这个函数名也给传递一次,一旦绑定,人家就知道了,对于led_work(),那她就嫁鸡随鸡,嫁狗随狗,嫁混蛋随混蛋了.您大概还有一个疑问,为什么只要这里初始化好了,到时候调用schedule_delayed_work()就可以了呢?事实上,events这么一个线程吧,它其实和hub的内核线程一样,有事情就处理,没事情就睡眠,也是一个死循环,schedule_delayed_work()的作用就是唤醒这个线程,确切的说,是先把自己的这个struct work_struct插入workqueue_struct这个队列里,然后唤醒昏睡中的events.然后events就会去处理,您要是有延时,那么它就给您安排延时以后执行,您要是没有延时,或者您设了延时为0,那好,那就赶紧给您执行.咱这里不是讲了两个宏吗,一个INIT_WORK(),一个INIT_DELAYED_WORK(),后者就是专门用于可以有延时的,而前者就是没有延时的,这里咱们调用的是INIT_DELAYED_WORK(),不过您别美,过一会您会看见INIT_WORK()也被使用了,因为咱们hub驱动中还有另一个地方也想利用工作队列这么一个机制,而它不需要延时,所以就使用INIT_WORK()进行初始化,然后在需要调用相关函数的时候调用schedule_work()即可.此乃后话,暂且不表.

    基本上这一节咱们就是介绍了Linux内核中工作队列机制提供的接口,两对函数INIT_DELAYED_WORK()schedule_delayed_work(),INIT_WORK()schedule_work().

    关于工作队列机制,咱们还会用到另外两个函数,它们是cancel_delayed_work(struct delayed_work *work)flush_scheduled_work().其中cancel_delayed_work()的意思不言自明,对一个延迟执行的工作来说,这个函数的作用是在这个工作还未执行的时候就把它给取消掉.flush_scheduled_work()的作用,是为了防止有竞争条件的出现,虽说哥们儿也不是很清楚如何防止竞争,可是好歹大二那年学过一门专业课,数字电子线路,尽管没学到什么有用的东西,怎么说也还是记住了两个专业名词,竞争与冒险.您要是对竞争条件不是很明白,那也不要紧,反正基本上每次cancel_delayed_work之后您都得调用flush_scheduled_work()这个函数,特别是对于内核模块,如果一个模块使用了工作队列机制,并且利用了events这个缺省队列,那么在卸载这个模块之前,您必须得调用这个函数,这叫做刷新一个工作队列,也就是说,函数会一直等待,直到队列中所有对象都被执行以后才返回.当然,在等待的过程中,这个函数可以进入睡眠.反正刷新完了之后,这个函数会被唤醒,然后它就返回了.关于这里这个竞争,可以这样理解,events对应的这个队列,人家本来是按部就班的执行,一个一个来,您要是突然把您的模块给卸载了,或者说你把你的那个工作从工作队列里取出来了,events作为队列管理者,它可能根本就不知道,比如说它先想好了,下午3点执行队列里的第N个成员,可是您突然把第N-1个成员给取走了,那您说这是不是得出错?所以,为了防止您这种唯恐天下不乱的人做出冒天下之大不韪的事情来,提供了一个函数,flush_scheduled_work(),给您调用,以消除所谓的竞争条件,其实说竞争太专业了点,说白了就是防止混乱吧.

    Ok,关于这些接口就讲到这里,日后咱们自然会在hub驱动里见到这些接口函数是如何被使用的.到那时候再来看.这就是蝴蝶效应.当我们看到INIT_WORK/INIT_DELAYED_WORK()的时候,我们是没法预测未来会发生什么的.所以我们只能拭目以待.又想起了那句老话,大学生活就像被强奸,如果不能反抗,那就只能静静的去享受它.


    展开全文
  • linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/gpio.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/platform_...

    先上代码,代码如下:

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/gpio.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h>
    #include <linux/platform_device.h>
    #include <linux/of_gpio.h>
    #include <linux/device.h>
    #include <linux/ioctl.h>
    #include <linux/err.h>
    #include <linux/list.h>
    #include <linux/errno.h>
    #include <linux/slab.h>
    #include <linux/compat.h>
    #include <linux/of.h>
    #include <linux/of_device.h>
    #include <linux/irq.h>
    #include <linux/of_irq.h>
    #include <linux/interrupt.h>
    #include <linux/clk-provider.h>
    #include <linux/clk/ti.h>
    #include <linux/clk.h>
    #include <linux/io.h>
    #include <linux/of_address.h>
    #include <linux/delay.h>
    #include <linux/sched.h>
    #include <linux/timer.h>
    #include <linux/workqueue.h>
    
    
    #define WORK_DELAY_VALUE	1
    static struct delayed_work delay_work1;
    
    //延时时间到时,开始执行下面的函数
    static void delay_work_func(struct work_struct *work)
    {
        printk("this is delay_work_func !\n");
        //自己再启动自己,也可以在其他地方启动
    	schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));	
    }
    
    
    static int __init mod_init(void)
    {
        //初始化delay_work1,绑定执行函数
    	INIT_DELAYED_WORK(&delay_work1, delay_work_func);
        //调用启动延时工作队列
    	schedule_delayed_work(&delay_work1, msecs_to_jiffies(WORK_DELAY_VALUE));	
    	return 0; 
    }
    module_init(mod_init);
    
    static void __exit mod_exit(void)
    {
    	cancel_delayed_work_sync(&delay_work1);
    	printk("############### %s  %s !kernel\n", __FILE__, __func__);
    }
    module_exit(mod_exit);
    
    
    MODULE_AUTHOR("lqd");
    MODULE_LICENSE("GPL");
    
    

    延时工作队列里面用到的延时msecs_to_jiffies时间设置,和之前介绍的 Linux 定时器的简单使用 里面的HZ是类似的。

    展开全文
  • docker安装rabbitMQ延时队列插件(delayed_message_exchange) 1. 查找Docker容器中的RabbitMQ镜像 docker ps -a [root@linux ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS

    docker安装rabbitMQ延时队列插件(delayed_message_exchange)

    • 1. 查找Docker容器中的RabbitMQ镜像

    docker ps -a

    [root@linux ~]# docker ps -a
    CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                                                                                        NAMES
    8efd6f3add3c        chenchuxin/dubbo-admin   "catalina.sh run"        6 weeks ago         Up 5 weeks          0.0.0.0:9090->8080/tcp                                                                       dubbo-admin
    6939b83d0942        zookeeper                "/docker-entrypoint.…"   6 weeks ago         Up 5 weeks                                                                                                       zookeeper01
    2aec2548a9f8        525bd2016729             "docker-entrypoint.s…"   6 weeks ago         Up 5 weeks          0.0.0.0:27017->27017/tcp                                                                     docker_mongodb
    
    
    • 2.上传rabbitmq_delayed_message_exchange-20171201-3.7.x.ez插件到Linux文件夹中

    下载解压文件  https://download.csdn.net/download/zhangdaiscott/13130449

    • 3.拷贝插件文件到rabbitMQ的Docker容器中
    [root@linux ~]# docker cp rabbitmq_delayed_message_exchange-20171201-3.7.x.ez rabbitmq3.7.7:/plugins
    
    
    • 4.进入rabbitMQ的Docker容器中docker exec -it rabbitmq3.7.7 bash
    [root@linux ~]# docker exec -it rabbitmq3.7.7 bash
    root@myRabbit:/# 
    
    
    • 5.查看插件列表
    rabbitmq-plugins list
    
    • 6.启用插件
    rabbitmq-plugins enable rabbitmq_delayed_message_exchange
    
    展开全文
  • 工作队列(work queue)是Linux内核中将操作延期执行的一种机制。因为它们是通过守护进程在用户上下文执行,函数可以睡眠的时间,与内核是无关的。在内核版本2.5开发期间,设计了工作队列,用以替换此前的keventd机制...

    在linux中,当你想延时几秒或者几毫秒再执行一个任务或者自定义的一个函数时,延时工作队列是你最好的选择。在你的任务或者函数中,加上queue_delayed_work,就可以每隔一段时间执行一次你的任务或者自定义的一个函数,具体实现如下:

    按如下步骤:

    首先还是要添加上工作队列的相关头文件,头文件一般有这些函数的声明和定义,include了相关的头文件,我们才能随心所欲的使用这些头文件里面的函数,达到我们的目的:

    #include <linux/workqueue.h>
    

    一.声明一个工作队列

    static struct workqueue_struct *test_wq;
    

    二.声明一个延期工作描述实例

    static struct delayed_work test_delay_wq;
    

    三.声明并实现一个工作队列延迟处理函数

    void test_power_delay_work_func(struct work_struct *work)
     {
            int value;
    
       value = get_adc_sample(0, CHAN_1);  //这里调用adc接口去读取数据
        pr_err("-czd-: current power adc value is %d\n", value);
    
       queue_delayed_work(test_wq, &test_delay_wq, msecs_to_jiffies(5000)); //加上这句就可以每隔5秒钟执行一次这个函数test_power_delay_work_func,不加就只执行一次,时间msecs_to_jiffies(5000)可以设置别的时间,这里是5秒,相关部分想了解更多可以百度
     }
    

    四.初始化一个工作队列(在init模块加载函数添加或者在probe函数添加)

    test_wq = create_workqueue("test_wq");
    if (!test_wq) {  
            printk(-czd-: No memory for workqueue\n");  
            return 1;     
        } 
    

    五. 任务初始化(在init模块加载函数添加或者在probe函数添加)

    INIT_DELAYED_WORK(&test_delay_wq, test_power_delay_work_func);
    

    六.向工作队列提交工作项(在init模块加载函数添加或者在probe函数添加)

    ret = queue_delayed_work(test_wq, &test_delay_wq, msecs_to_jiffies(5000));
    pr_err("-czd-: ret=%d\n", ret);
    

    七.取消工作队列中的工作项

    int cancel_delayed_work(test_wq);
    

    如果这个工作项在它开始执行前被取消,返回值是非零。内核保证给定工作项的执行不会在调用 cancel_delay_work 成功后被执行。 如果 cancel_delay_work 返回 0,则这个工作项可能已经运行在一个不同的处理器,并且仍然可能在调用 cancel_delayed_work 之后被执行。要绝对确保工作函数没有在 cancel_delayed_work 返回 0 后在任何地方运行,你必须跟随这个调用之后接着调用 flush_workqueue。在 flush_workqueue 返回后。任何在改调用之前提交的工作函数都不会在系统任何地方运行。

    八.刷新工作队列

    flush_workqueue(test_wq);
    

    九.工作队列销毁

    destroy_workqueue(test_wq);
    

    七八九可以同时添加到exit函数中,例如以下:

    static void __exit module_exit(void)  
    {  
    
       int ret;  
        ret = cancel_delayed_work(&test_dwq);  
        flush_workqueue(test_wq);
        destroy_workqueue(test_wq);
       printk("-czd-: enter %s, ret=%d\n", __func__,  ret);  
    }
    

    除了上面调用的queue_delayed_work之外,使用schedule_delayed_work也是可以的。其实schedule_delayed_work最终返回调用的还是queue_delayed_work。函数声明在include/linux/workqueue.h中。

     static inline bool schedule_delayed_work(struct delayed_work *dwork,
                                              unsigned long delay)
     {
             return queue_delayed_work(system_wq, dwork, delay);
     }
    

    下面的demo是实现3秒之后再执行work_queue:

    	#include <linux/workqueue.h>
    	static struct delayed_work send_event; //定义一个delay_work
    
    
    	static void send_event_workq(struct work_struct *work)  //定义你要延时执行的函数
    	{
        rk_send_wakeup_key();
    	   printk("***************charger mode send wakeup key\n\n");
    	   schedule_delayed_work(&send_event, msecs_to_jiffies(3000)); //添加之后每隔3秒执行一次
    	}
    
    
    	 static int  __init module_init(void)
    	 {
    
     	  INIT_DELAYED_WORK(&send_event, send_event_workq); //初始化工作队列
     	   schedule_delayed_work(&send_event, msecs_to_jiffies(3000)); //添加到延时工作队列,这里延时3秒
    	}
    
    	static void __exit module_exit(void)  
    	{  
     
        cancel_delayed_work_sync(&send_event);  //取消延时工作队列
    	} 
    

    下面是创建一个工作队列的demo 代码:

    	#include <linux/workqueue.h>
    	void my_func(void *data)
    	{
        char *name = (char *)data;
        printk(KERN_INFO “Hello world, my name is %s!\n”, name);
    	}
    
    	struct workqueue_struct *my_wq = create_workqueue(“my wq”);
    	struct work_struct my_work;
    
    	INIT_WORK(&my_work, my_func);
    	queue_work(my_wq, &my_work);
    
    	destroy_workqueue(my_wq);
    
    展开全文
  • linux工作队列

    2017-07-02 18:43:17
    linux内核自带的用于开销量比较小的工作队列,用户不能长时间独占该队列 自定义工作队列: 如果队列上有很多的工作存在阻塞的情况下,用户自定义工作队列就不会受其他工作队列的影响了,但是这样会导致系统的开销比较...
  • Linux工作队列

    2017-11-15 13:40:56
    Linux中的等待队列有两种,一种是普通的work queue,还有一种是可以给定延时多久以后执行的work queue,相比普通的来说,其多了延时时间这个参数,下面将具体介绍下应该如何使用这两种work queue。   1. 普通w
  • docker安装rabbitMQ延时队列插件(delayed_message_exchange)1. 查找Docker容器中的RabbitMQ镜像 docker ps -a[root@linux ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED ...
  • linux中断编程中,需要中断程序分成中断顶部和中断底部两部分,顶部...底部分代码实现可以通过内核共享工作队列实现。 1)核心结构 Workqueue.h include\Linux struct work_struct { atomic_long_t data; ...
  • linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/gpio.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/platform_...
  • linux 工作队列

    2014-02-13 15:35:15
    工作队列是实现延迟的新机制,从 2.5 版本 Linux 内核开始提供该功能。不同于微线程一步到位的延迟方法,工作队列采用通用的延迟机制, 工作队列的处理程序函数能够休眠(这在微线程模式下无法实现)。 工作...
  • 本文使用的是linux版本的RabbitMQ,版本是: rabbitmq-server-3.6.15-1.el6.noarch.rpm rabbitmq_delayed_message_exchange插件 插件下载地址: http://www.rabbitmq.com/community-plugins.html 由于我安装的...
  • Linux公平队列FQ配置

    2020-09-04 21:43:32
    FQ (Fair Queue)是一个无类别(classless)的报文调度器,其主意用于本地产生的流量。设计为控制每个流的发送节奏(pacing)。FQ完成流的区分,并且可完成TCP层要求的发送...FQ调度器可在发送报文之间增加延时以达到T
  • Linux延时处理

    2016-08-06 17:01:30
    1、Linux延时处理 设备驱动经常需要将某些特定代码延迟一段时间后执行--通常是为了让硬件能完成某些任务。  1.1长延时   超时 如果驱动程序使用等待队列来等待其他一些事件,而我们同时希望在特定时间段中运行...
  • 文章目录Linux内核延时概念应用场景Linux内核相关延时函数Linux内核等待队列机制概述等待队列的功能驱动编程实施步骤示例代码(一)示例代码(二)总结 Linux内核延时 概念 延时又称为等待,延时分为两类:忙延时和...
  • rabbitMQ 中必须是Disc(磁盘型)类型的节点才可以安装延时队列插件, RAM(内存型)类型节点无法安装。 1.通过 rpm -qa|grep rabbit 命令查看当前linux是否安装RabbitMQ [root@linux]# rpm -qa|grep

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 155
精华内容 62
关键字:

linux延时队列

linux 订阅