queue 订阅
队列是一种特殊的线性表,是一种先进先出(FIFO)的数据结构。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。 展开全文
队列是一种特殊的线性表,是一种先进先出(FIFO)的数据结构。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
信息
外文名
queue
属    于
编程
类    别
计算机
中文名
队列
性    质
科学
queue简介
在队列这种数据结构中,最先插入在元素将是最先被删除;反之最后插入的元素将最后被删除,因此队列又称为“先进先出”(FIFO—first in first out)的线性表。队列空的条件:front=rear队列满的条件: rear = MAXSIZE队列可以用数组Q[1…m]来存储,数组的上界m即是队列所容许的最大容量。在队列的运算中需设两个指针:head,队头指针,指向实际队头元素的前一个位置;tail,队尾指针,指向实际队尾元素所在的位置。一般情况下,两个指针的初值设为0,这时队列为空,没有元素。图1 ( a)画出了一个由6个元素构成的队列,数组定义Q[1…10]。Q(i) i=3,4,5,6,7,8头指针head=2,尾指针tail=8。队列中拥有的元素个数为:L=tail-head现要让排头的元素出队,则需将头指针加1。即head=head+1这时头指针向上移动一个位置,指向Q(3),表示Q(3)已出队。见图1 (b)。如果想让一个新元素入队,则需尾指针向上移动一个位置。即tail=tail+1这时Q(9)入队。当队尾已经处理在最上面时,即tail=10,如果还要执行入队操作,则要发生"上溢",但实际上队列中还有三个空位置,所以这种溢出称为"假溢出"。克服假溢出的方法有两种。一种是将队列中的所有元素均向低地址区移动,显然这种方法是很浪费时间的;另一种方法是将数组存储区看成是一个首尾相接的环形区域。当存放到n地址后,下一个地址就"翻转"为1。在结构上采用这种技巧来存储的队列称为循环队列。队列和栈一样只允许在端点(前端或者后端)处插入和删除元素。循环队的入队算法如下:1、tail=tail+1;2、若tail=n+1,则tail=1;3、若head=tail尾指针与头指针重合了,表示元素已装满队列,则作上溢出错处理;4、否则,Q(tail)=X,结束(X为新入出元素)。队列和栈一样,有着非常广泛的应用。
收起全文
精华内容
下载资源
问答
  • 2019-01-10 09:50:32

    相关连接:https://blog.csdn.net/knowledgebao/article/details/84621238


    queue/queue2/multiqueue

    queue:

    queue只有一个src pad和一个sink pad,会在src pad上创建一个线程,减少src和sink的关联。queue有三个限制参数buffers、bytes、time(单位纳秒ns)。有最大阀值和最小阀值供6个参数。最大默认值:200 buffers、10MB、one second,最小默认值都是0.

    当三个限制参数某一个达到最大值的时候,会阻塞上游的链路传输(可以通过设置属性 “leaky” property 来处理阻塞情况,分为上游丢弃或下游丢弃或不丢弃阻塞)。“overrun” signal会被发送,当数据达到最高阀值的时候,“underrun” signal 会被发送,当数据达到最低阀值的时候。

     “current-level-buffers” property可以获取当前buffers的个数。notify::current-level-buffers signal 可以监听buffers的变动。bytes和time也有类似的属性和信号。

    queue2:

    和queue的区别如下:

    1. 默认值不同:最大值:100 buffers, 2MB,  two seconds,最小值默认都是0.
    2. 增加了temp-template属性比如:/tmp/gstreamer-XXXXXX,设置此属性后,数据会被保存到文件中,具体文件名可以通过属性temp-location获取。
    3. 一些属性发生了变化,比如:只有“overrun” 信号,增加循环buf,增加GST_MESSAGE_BUFFERING消息等

    multiqueue:

    和queue的区别如下:

    1. src pad和sink pad由1个变成了多个。When requesting a given sinkpad with gst_element_request_pad(), the associated srcpad for that stream will be created. 如果stream超过一个,对应的queue也会增长,保证不会饿死。
    2. 当src pad没有下游连接的时候,sink pad的内容也会发给src pad。sink pad和src pad总是成对出现,创建sink pad的时候回同步创建src pad。当src pad和下游处于unlink的时候,buffers和envet由sink pad发送给src pad的时候必须按照先后顺序发送。针对这样情况有一个属性“sync-by-running-time”,当此属性设置为true时,非link的stream也会参考link的stream的runing time来同步。
    3. 默认值不同:最大值:5 buffers, 10MB,  two second ,最小值默认都是0.
    4. The “underrun” signal is emitted when all of the queues are empty. The “overrun” signal is emitted when one of the queues is filled. 
    5. 当有多个src pad的时候,对应多个线程,类似于多个queue,其中max-size-buffers等也有多份,只不过都相同而已。

     

    queue:内存单队列

    Object Hierarchy

        GObject
        ╰── GInitiallyUnowned
            ╰── GstObject
                ╰── GstElement
                    ╰── GstQueue

    Properties

    guintcurrent-level-buffersRead当前队列中buffers大小
    guintcurrent-level-bytesRead当前队列中bytes大小
    guint64current-level-timeRead当前队列中包含数据time大小,单位ns
    gbooleanflush-on-eosRead / Write是否支持eos events处理。
    GstQueueLeakyleakyRead / Writequeue满时的处理策略。阻塞,扔新数据,扔旧数据
    guintmax-size-buffersRead / Writequeue中允许的最大buffers
    guintmax-size-bytesRead / Writequeue中允许的最大bytes
    guint64max-size-timeRead / Writequeue中允许的最大time,单位ns
    guintmin-threshold-buffersRead / Writequeue中允许发送的最小buffers
    guintmin-threshold-bytesRead / Writequeue中允许发送的最小bytes
    guint64min-threshold-timeRead / Writequeue中允许发送的最小time
    gbooleansilentRead / Write是否支持发送信号,默认为FALSE

    Signals

    voidoverrunRun Firstqueue满时发送的信号,silent必须为TRUE(下同)
    voidpushingRun Firstqueue由空闲变为有数据时发送的信号。
    voidrunningRun First当queue阻塞且由满变为有空闲的时候发送。或pushing满足的时候也发送。
    voidunderrunRun Firstqueue三个限制条件都低于给定值时发送的信号

    Types and Values

    structGstQueueOpaque GstQueue structure.透明结构体,无需了解
    enumGstQueueLeaky

    GST_QUEUE_NO_LEAK阻塞

    GST_QUEUE_LEAK_UPSTREAM丢新数据

    GST_QUEUE_LEAK_DOWNSTREAM丢旧数据


    Description

    Data is queued until one of the limits specified by the “max-size-buffers”“max-size-bytes” and/or “max-size-time”properties has been reached. Any attempt to push more buffers into the queue will block the pushing thread until more space becomes available.

    The queue will create a new thread on the source pad to decouple the processing on sink and source pad.

    You can query how many buffers are queued by reading the “current-level-buffers” property. You can track changes by connecting to the notify::current-level-buffers signal (which like all signals will be emitted from the streaming thread). The same applies to the “current-level-time” and “current-level-bytes” properties.

    The default queue size limits are 200 buffers, 10MB of data, or one second worth of data, whichever is reached first.

    As said earlier, the queue blocks by default when one of the specified maximums (bytes, time, buffers) has been reached. You can set the “leaky” property to specify that instead of blocking it should leak (drop) new or old buffers.

    The “underrun” signal is emitted when the queue has less data than the specified minimum thresholds require (by default: when the queue is empty). The “overrun” signal is emitted when the queue is filled up. Both signals are emitted from the context of the streaming thread.

    Synopsis

    Element Information

    plugin

    coreelements

    author

    Erik Walthinsen <omega@cse.ogi.edu>

    class

    Generic

    Element Pads

    name

    sink

    direction

    sink

    presence

    always

    details

    ANY

    name

    src

    direction

    source

    presence

    always

    details

    ANY

    queue2:文件单队列

    Object Hierarchy

        GObject
        ╰── GInitiallyUnowned
            ╰── GstObject
                ╰── GstElement
                    ╰── GstQueue2

    Properties

    guintcurrent-level-buffersRead参考queue
    guintcurrent-level-bytesRead参考queue
    guint64current-level-timeRead参考queue
    ginthigh-percentRead / Write废弃,Deprecated: use high-watermark instead
    gintlow-percentRead / Write废弃,Deprecated: use low-watermark instead
    guintmax-size-buffersRead / Write参考queue
    guintmax-size-bytesRead / Write参考queue
    guint64max-size-timeRead / Write参考queue
    guint64ring-buffer-max-sizeRead / Write循环buf的最大个数,为0不用循环buf
    gchar *temp-locationRead文件名,系统根据temp-template生成
    gbooleantemp-removeRead / Write使用完成后,清除临时文件
    gchar *temp-templateRead / Write设置生成文件模板,类似:/tmp/gstreamer-XXXXXX
    gbooleanuse-bufferingRead / Write是否发送 GST_MESSAGE_BUFFERING消息。
    gbooleanuse-rate-estimateRead / WriteEstimate the bitrate of the stream to calculate time level.
    gint64avg-in-rateReadThe average input data rate.
    gbooleanuse-tags-bitrateRead / WriteUse a bitrate from upstream tags to estimate buffer duration if not provided.
    gdoublehigh-watermarkRead / Write触发GST_MESSAGE_BUFFERING消息的上限[0~1],默认0.99
    gdoublelow-watermarkRead / Write触发GST_MESSAGE_BUFFERING消息的下限[0~1],默认0.01

    Signals

    voidoverrunRun First参考queue

    Types and Values

    structGstQueue2Opaque GstQueue2 structure.透明结构体,无需了解


    Description

    Data is queued until one of the limits specified by the “max-size-buffers”“max-size-bytes” and/or “max-size-time”properties has been reached. Any attempt to push more buffers into the queue will block the pushing thread until more space becomes available.

    The queue will create a new thread on the source pad to decouple the processing on sink and source pad.

    You can query how many buffers are queued by reading the “current-level-buffers” property.

    The default queue size limits are 100 buffers, 2MB of data, or two seconds worth of data, whichever is reached first.

    If you set temp-template to a value such as /tmp/gstreamer-XXXXXX, the element will allocate a random free filename and buffer data in the file. By using this, it will buffer the entire stream data on the file independently of the queue size limits, they will only be used for buffering statistics.

    The temp-location property will be used to notify the application of the allocated filename.

    Synopsis

    Element Information

    plugin

    coreelements

    author

    Erik Walthinsen <omega@cse.ogi.edu>, Wim Taymans <wim.taymans@gmail.com>

    class

    Generic

    Element Pads

    name

    sink

    direction

    sink

    presence

    always

    details

    ANY

    name

    src

    direction

    source

    presence

    always

    details

    ANY

    multiqueue:内存多队列

    Object Hierarchy

        GObject
        ╰── GInitiallyUnowned
            ╰── GstObject
                ╰── GstElement
                    ╰── GstMultiQueue

    Properties

    guintextra-size-buffersRead / Write暂时未实现
    guintextra-size-bytesRead / Write暂时未实现
    guint64extra-size-timeRead / Write暂时未实现
    ginthigh-percentRead / Write类似high-watermark,取值范围[0,100],queue2此值以放弃
    gintlow-percentRead / Write类似low-watermark,取值范围[0,100],queue2此值以放弃
    guintmax-size-buffersRead / Write参考queue
    guintmax-size-bytesRead / Write参考queue
    guint64max-size-timeRead / Write参考queue
    gbooleansync-by-running-timeRead / Write设置为true时,非link的stream也会参考link的stream的runing time来同步
    gbooleanuse-bufferingRead / Write参考queue2
    guint64unlinked-cache-timeRead / WriteExtra buffering in time for unlinked streams (if 'sync-by-running-time').Default value: 250000000
    gbooleanuse-interleaveRead / WriteAdjust time limits based on input interleave.是否使用interleave.multiqueue: New "use-interleave" property which allows the size of the queues to be optimized based on the input streams interleave. This should only be used with input streams which are properly timestamped. It will be used in the future decodebin3 element.
    gdoublehigh-watermarkRead / Write参考queue2
    gdoublelow-watermarkRead / Write参考queue2
    guint64min-interleave-timeRead / WriteMinimum extra buffering for deinterleaving (size of the queues) when use-interleave=true.

    Signals

    voidoverrunRun First参考queue,任意一个满都触发
    voidunderrunRun First参考queue,所有都不足才触发

    Types and Values

    structGstMultiQueueOpaque GstMultiQueue structure.透明结构体,无需了解


    Description

    Multiqueue is similar to a normal GstQueue with the following additional features:

    1) Multiple streamhandling

    • The element handles queueing data on more than one stream at once. To achieve such a feature it has request sink pads (sinku) and 'sometimes' src pads (srcu). When requesting a given sinkpad with gst_element_request_pad(), the associated srcpad for that stream will be created. Example: requesting sink1 will generate src1.

    2) Non-starvation on multiple stream

    • If more than one stream is used with the element, the streams' queues will be dynamically grown (up to a limit), in order to ensure that no stream is risking data starvation. This guarantees that at any given time there are at least N bytes queued and available for each individual stream. If an EOS event comes through a srcpad, the associated queue will be considered as 'not-empty' in the queue-size-growing algorithm.

    3) Non-linked srcpads graceful handling

    • In order to better support dynamic switching between streams, the multiqueue (unlike the current GStreamer queue) continues to push buffers on non-linked pads rather than shutting down. In addition, to prevent a non-linked stream from very quickly consuming all available buffers and thus 'racing ahead' of the other streams, the element must ensure that buffers and inlined events for a non-linked stream are pushed in the same order as they were received, relative to the other streams controlled by the element. This means that a buffer cannot be pushed to a non-linked pad any sooner than buffers in any other stream which were received before it.

    Data is queued until one of the limits specified by the “max-size-buffers”“max-size-bytes” and/or “max-size-time”properties has been reached. Any attempt to push more buffers into the queue will block the pushing thread until more space becomes available. “extra-size-buffers”,

    “extra-size-bytes” and “extra-size-time” are currently unused.

    The default queue size limits are 5 buffers, 10MB of data, or two second worth of data, whichever is reached first. Note that the number of buffers will dynamically grow depending on the fill level of other queues.

    The “underrun” signal is emitted when all of the queues are empty. The “overrun” signal is emitted when one of the queues is filled. Both signals are emitted from the context of the streaming thread.

    When using “sync-by-running-time” the unlinked streams will be throttled by the highest running-time of linked streams. This allows further relinking of those unlinked streams without them being in the future (i.e. to achieve gapless playback). When dealing with streams which have got different consumption requirements downstream (ex: video decoders which will consume more buffer (in time) than audio decoders), it is recommended to group streams of the same type by using the pad "group-id" property. This will further throttle streams in time within that group.

    Synopsis

    Element Information

    plugin

    coreelements

    author

    Edward Hervey <edward@fluendo.com>

    class

    Generic

    Element Pads

    name

    sink_%u

    direction

    sink

    presence

    request

    details

    ANY

    name

    src_%u

    direction

    source

    presence

    sometimes

    details

    ANY

     

    参考资料:

    1. queue
    2. queue2
    3. multiqueue
    4. 源码

    有任何问题,请联系:knowledgebao@163.com

    更多相关内容
  • C语言头文件 QUEUE.H

    2022-06-13 07:08:44
    C语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言头文件 QUEUE.HC语言...
  • nginx之queue

    千次阅读 2022-04-04 10:18:44
    nginx之queue类型

    一、简介

    ​ nginx队列和linux内核中的链表有一样的结构,只有一个连接头(只有两个指针),任何包含这个结构的数据都可以连接在一起。有点像物联网,万物互联,只要能上网都可以连接。

    ​ nginx队列是带头节点的一个双向链表。

    二、数据结构

    typedef struct ngx_queue_s  ngx_queue_t;
    
    struct ngx_queue_s {
        ngx_queue_t  *prev;
        ngx_queue_t  *next;
    };
    

    在这里插入图片描述

    三、相关API

    3.1 初始化一个队列

    #define ngx_queue_init(q)                                                     \
        (q)->prev = q;                                                            \
        (q)->next = q
    

    在这里插入图片描述

    3.2 判断队列是否为空

    只有一个头节点,则为空。有头节点的双向链表相比无头的双向链表,各种插入、删除等操作都更简单。

    #define ngx_queue_empty(h)                                                    \
        (h == (h)->prev)
    

    3.3 队头插入节点

    #define ngx_queue_insert_head(h, x)                                           \
        (x)->next = (h)->next;                                                    \
        (x)->next->prev = x;                                                      \
        (x)->prev = h;                                                            \
        (h)->next = x
    

    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    头部插入节点后
    在这里插入图片描述

    3.4 队尾插入节点

    #define ngx_queue_insert_tail(h, x)                                           \
        (x)->prev = (h)->prev;                                                    \
        (x)->prev->next = x;                                                      \
        (x)->next = h;                                                            \
        (h)->prev = x
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述尾部插入节点后
    在这里插入图片描述

    3.5 从队列中移除某个节点

    #define ngx_queue_remove(x)                                                   \
        (x)->next->prev = (x)->prev;                                              \
        (x)->prev->next = (x)->next
    

    在这里插入图片描述
    在这里插入图片描述移除x节点后
    在这里插入图片描述
    可以看到移除节点x后,x和队列还有一定的联系,所以对x的操作一定要小心,不然可能将整个队列损坏。 一般将x->prev,x->next都置空。

    3.6 将队列从某个节点拆分成两个队列

    #define ngx_queue_split(h, q, n)                                              \
        (n)->prev = (h)->prev;                                                    \
        (n)->prev->next = n;                                                      \
        (n)->next = q;                                                            \
        (h)->prev = (q)->prev;                                                    \
        (h)->prev->next = h;                                                      \
        (q)->prev = n;
    

    将队列h从节点q拆分为h和n两个队列,并且q节点在n队列中。
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    拆分完后
    在这里插入图片描述

    3.7 将两个队列合并成一个队列

    #define ngx_queue_add(h, n)                                                   \
        (h)->prev->next = (n)->next;                                              \
        (n)->next->prev = (h)->prev;                                              \
        (h)->prev = (n)->prev;                                                    \
        (h)->prev->next = h;
    

    在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    合并后
    在这里插入图片描述

    3.8 队列排序

    #define ngx_queue_head(h)                                                     \
        (h)->next
    
    
    #define ngx_queue_last(h)                                                     \
        (h)->prev
    
    
    #define ngx_queue_sentinel(h)                                                 \
        (h)
    
    
    #define ngx_queue_next(q)                                                     \
        (q)->next
    
    
    #define ngx_queue_prev(q)                                                     \
        (q)->prev
    
    #define ngx_queue_insert_after   ngx_queue_insert_head
    

    使用标准的插入排序算法,通过传递的回调函数cmp进行比较,将整个队列排序。

    void
    ngx_queue_sort(ngx_queue_t *queue,
        ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
    {
        ngx_queue_t  *q, *prev, *next;
    
        q = ngx_queue_head(queue);
    
        if (q == ngx_queue_last(queue)) {
            return;
        }
    
        for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {
    
            prev = ngx_queue_prev(q);
            next = ngx_queue_next(q);
    
            ngx_queue_remove(q);
    
            do {
                if (cmp(prev, q) <= 0) {
                    break;
                }
    
                prev = ngx_queue_prev(prev);
    
            } while (prev != ngx_queue_sentinel(queue));
    
            ngx_queue_insert_after(prev, q);
        }
    }
    

    3.9 获取队列中间节点

    通过快慢指针的方式获取中间节点。

    ngx_queue_t *
    ngx_queue_middle(ngx_queue_t *queue)
    {
        ngx_queue_t  *middle, *next;
    
        middle = ngx_queue_head(queue);
    
        if (middle == ngx_queue_last(queue)) {
            return middle;
        }
    
        next = ngx_queue_head(queue);
    
        for ( ;; ) {
            middle = ngx_queue_next(middle);
    
            next = ngx_queue_next(next);
    
            if (next == ngx_queue_last(queue)) {
                return middle;
            }
    
            next = ngx_queue_next(next);
    
            if (next == ngx_queue_last(queue)) {
                return middle;
            }
        }
    }
    

    3.10 获取原始数据

    #define ngx_queue_data(q, type, link)                                         \
        (type *) ((u_char *) q - offsetof(type, link))
    

    从队列中获取的节点类型都是ngx_queue_s,而不是实际的数据类型,需要将ngx_queue_s转换为原始的类型。其中offsetof是一个内置的表达式,计算某个成员变量在类型中的偏移量。
    通过偏移计算到计算到原始类型地址,然后进行类型强转获取原始类型。
    比如如下调用

    q = ngx_queue_last(&cache->expire_queue);
    file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
    

    在这里插入图片描述
    q的地址减去offset获取到ngx_cached_open_file_t的地址,然后在强转为对应的类型。

    展开全文
  • 关于rabbitmq的原生api和spring amqp的api的动态绑定exchange,routingKey,queue 说明文地址: http://blog.csdn.net/phantomes/article/details/47284829
  • libuv 源码分析 —— 1.queue

    千次阅读 2022-04-05 14:09:28
    typedef void *QUEUE[2]; 使用QUEUE q; // 相当于 void *q[2] 定义基本操作 #define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) #define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) #define QUEUE_...

    定义指针数组类型

    typedef void *QUEUE[2];
    
    • 使用
      QUEUE q;	// 相当于 void *q[2]
      

    在这里插入图片描述

    定义基本操作

    #define QUEUE_NEXT(q)       (*(QUEUE **) &((*(q))[0]))
    #define QUEUE_PREV(q)       (*(QUEUE **) &((*(q))[1]))
    #define QUEUE_PREV_NEXT(q)  (QUEUE_NEXT(QUEUE_PREV(q)))
    #define QUEUE_NEXT_PREV(q)  (QUEUE_PREV(QUEUE_NEXT(q)))
    

    QUEUE_NEXT

    • 使用
      QUEUE queue;
      // 返回值是下一个节点QUEUE的指针
      QUEUE_NEXT(&queue);
      
    • (*(QUEUE **) &((*(q))[0])) 相当于 (*q)[0],为什么要写的这么复杂呢?主要有两个原因:类型保持、成为左值。
    • (*(q))[0]:首先,传入 q 的类型为 &QUEUE,那么 (*(q)) 类型为 QUEUE,(*(q))[0] 相当于 queue[0]
    • *(QUEUE **) &((*(q))[0]):queue[0] 的类型为 void*,那么 &(queue[0]) 的类型就为 void**,这可不行,明明应该是 QUEUE** 类型,怎么能是 void**,所以要进行 (QUEUE **) &((*(q))[0]) 类型转换。还是有问题,最后返回的是下一个节点QUEUE的指针,现在变成了指针的指针,所以还要对 (QUEUE **) &((*(q))[0]) 再次取值 *(QUEUE **) &((*(q))[0])
    • 这时候你该问了:为什么不能写成 (QUEUE*)(*(q))[0] 这样的呢?这是为了使其成为左值,左值的简单定义是:占用实际的内存、可以对其进行取地址操作的变量都是左值,而c语言中(其实其他语言也是一样),对于一个变量(或者表达式)进行强制类型转换时,其实并不是改变该变量本身的类型,而是产生一个变量的副本,而这个副本并不是左值(因为并不能对其取地址),它是一个右值,举个例子:int a = 1; (char) a = 2;这样会报错。而如果改成这样:int a = 1; (*(char *)(&a)) = 2;就正确了。
      在这里插入图片描述

    队列操作

    队列初始化

    #define QUEUE_INIT(q)                                                         \
      do {                                                                        \
        QUEUE_NEXT(q) = (q);                                                      \
        QUEUE_PREV(q) = (q);                                                      \
      }                                                                           \
      while (0)
    
    • 初始化队列q就是将其next和prev的指针指向自己

    队列为空判断

    #define QUEUE_EMPTY(q)                                                        \
      ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
    
    • 只要q的next指针还是指向自己,就说明队列为空(只有链表头结点)

    队列遍历

    #define QUEUE_FOREACH(q, h)                                                   \
      for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
    
    • 遍历队列q,直到遍历到h为止。注意:在遍历时,不要同时对队列q进行插入、删除操作,否则会出现未知错误

    获取队列头

    #define QUEUE_HEAD(q)                                                         \
       (QUEUE_NEXT(q))
    
    • 链表头节点的next返回的就是队列的head节点

    向队列头插入节点

    // prev 是下一个元素
    // next 是上一个元素
    #define QUEUE_INSERT_HEAD(h, q)                                               \
      do {                                                                        \
        QUEUE_NEXT(q) = QUEUE_NEXT(h);     	                                        \
        QUEUE_PREV(q) = (h);                                                      \
        QUEUE_NEXT_PREV(q) = (q);                                                 \
        QUEUE_NEXT(h) = (q);                                                      \
      }                                                                           \
      while (0)
    
    • 队列 h,p 的起始状态
      在这里插入图片描述

    • 插入【QUEUE_INSERT_HEAD(h, q)
      在这里插入图片描述

    • 再插入一个节点【QUEUE_INSERT_HEAD(h, n)
      在这里插入图片描述

    向队列尾部插入节点

    // prev 是下一个元素
    // next 是上一个元素
    #define QUEUE_INSERT_TAIL(h, q)                                               \
      do {                                                                        \
        QUEUE_NEXT(q) = (h);                                                      \
        QUEUE_PREV(q) = QUEUE_PREV(h);                                            \
        QUEUE_PREV_NEXT(q) = (q);                                                 \
        QUEUE_PREV(h) = (q);                                                      \
      }                                                                           \
      while (0)
    
    • 向队列尾部插入元素是【QUEUE_INSERT_HEAD(h, q)
      在这里插入图片描述

    队列相加

    #define QUEUE_ADD(h, n)                                                       \
      do {                                                                        \
        QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n);                                       \
        QUEUE_NEXT_PREV(n) = QUEUE_PREV(h);                                       \
        QUEUE_PREV(h) = QUEUE_PREV(n);                                            \
        QUEUE_PREV_NEXT(h) = (h);                                                 \
      }                                                                           \
      while (0)
    

    队列分割

    #define QUEUE_SPLIT(h, q, n)                                                  \
      do {                                                                        \
        QUEUE_PREV(n) = QUEUE_PREV(h);                                            \
        QUEUE_PREV_NEXT(n) = (n);                                                 \
        QUEUE_NEXT(n) = (q);                                                      \
        QUEUE_PREV(h) = QUEUE_PREV(q);                                            \
        QUEUE_PREV_NEXT(h) = (h);                                                 \
        QUEUE_PREV(q) = (n);                                                      \
      }                                                                           \
      while (0)
    
    • 队列分割就是上述ADD的逆过程,将队列h以q为分割点进行分割,分割出来的新队列为n(n为分出来的双向循环链表的头结点)

    队列移动

    #define QUEUE_MOVE(h, n)                                                      \
      do {                                                                        \
        if (QUEUE_EMPTY(h))                                                       \
          QUEUE_INIT(n);                                                          \
        else {                                                                    \
          QUEUE* q = QUEUE_HEAD(h);                                               \
          QUEUE_SPLIT(h, q, n);                                                   \
        }                                                                         \
      }                                                                           \
      while (0)
    
    • 将队列h移动到n队里中,首先如果h队列为空,那么就把n初始化为空;如果h不为空,那么就先取出h队列的head节点,然后调用前面论述过的队列分割宏,从head节点开始分割,等价于把h队列的所有内容(输了h自身,因为它是链表头节点)全部转移到n队里里面

    队列删除

    #define QUEUE_REMOVE(q)                                                       \
       do {                                                                        \
         QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q);                                       \
         QUEUE_NEXT_PREV(q) = QUEUE_PREV(q);                                       \
       }                                                                           \
       while (0)
    
    • 队列删除的原理很简单,现将q前一个节点的next指针修改为指向q的next指针指向的下一个节点,再q的下一个节点的prev指针修改为指向q当前指向的前一个节点

    在队列中存取用户数据

    #define QUEUE_DATA(ptr, type, field)                                          \
       ((type *) ((char *) (ptr) - offsetof(type, field)))
    
    • 先讲解一下如何使用
    #include "queue.h"
    #include <stdio.h>
    
    static QUEUE* q;
    static QUEUE queue;
    
    struct user_s {
        int age;
        char* name;
    
        QUEUE node;
    };
    
    int main() {
        struct user_s* user;
        
        struct user_s john;
        john.name = "john";
        john.age = 44;
    
        struct user_s henry;
        henry.name = "henry";
        henry.age = 32;
        
        struct user_s willy;
        willy.name = "willy";
        willy.age = 99;
    
        QUEUE_INIT(&queue);
        QUEUE_INIT(&john.node);
        QUEUE_INIT(&henry.node);
        QUEUE_INIT(&willy.node);
    
        ((*(&queue))[0]) = john.node;
        (*(QUEUE **) &((*(&queue))[0])) = &john.node;
     
        QUEUE_INSERT_TAIL(&queue, &john.node);
        QUEUE_INSERT_TAIL(&queue, &henry.node);
        QUEUE_INSERT_TAIL(&queue, &willy.node);
    
        q = QUEUE_HEAD(&queue);
      
        user = QUEUE_DATA(q, struct user_s, node);
        
        printf("Received first inserted user: %s who is %d.\n",
            user->name, user->age);
        return 0;
    }
    
    • 现在看上面那段代码
      #define QUEUE_DATA(ptr, type, field)                                          \
         ((type *) ((char *) (ptr) - offsetof(type, field)))
      
      data 就是返回的数据部分
      在这里插入图片描述
    • 只要结构体中包含了 QUEUE 节点,可以将他们的node成员组成双向循环链表进行管理,这样就可以以队列方式来管理它们的node成员了。拿到node成员的地址之后,只要将该地址减去node成员在结构体中的偏移,就可以拿到整个结构体的起始地址,也就拿到了用户数据了。
    展开全文
  • Threadx 消息队列 queue

    千次阅读 2020-02-07 17:15:47
    系统中所有信号量控制块挂载一个双向链表_tx_queue_created_ptr中,tx_queue_created_next指向下一个消息队列指针,tx_queue_created_previous指向前一个消息队列指针。 消息队列API 函数 描述 ...


    Threadx提供了消息队列进行线程间通信。
    消息队列中消息通常按照先进先出规则传递,同时提供了把消息直接存储到队列头部的API。每个线程可以创建多个消息队列,并且可以使用多个消息队列和多个线程通信。
    消息队列不支持拥有者属性,也就是任何线程可以向消息队列发送或接收消息。应用开发者保证消息队列使用的合理性。

    消息传递规则

    1,任何线程可以向一个消息队列发送或接收消息,消息队列不支持拥有者属性。
    2,消息队列支持先进先出规则,函数_tx_queue_send发送消息都队列尾部。
    3,消息队列也支持发送消息到消息头部功能,函数_tx_queue_front_send发送消息到消息头部。
    4,如果消息队列有挂起的接收线程,发送消息时,可以直接把消息放到接收线程的缓冲中,这可以降低消息传递延时。
    TX_THREAD线程控制块中tx_additional_suspend_info域用于存储接收线程缓冲区地址。
    5,如果消息队列为空,接收线程调用_tx_queue_receive(wait_option不为0)读取消息时,线程会被挂起到队列tx_queue_suspension_list。其它线程发送消息后会恢复挂起的线程
    6,如果消息队列已满,发送线程调用_tx_queue_send(wait_option不为0)发送消息时,线程会被挂起到队列tx_queue_suspension_list。其它线程接收消息时,会恢复挂起的线程。

    在这里插入图片描述

    消息大小

    消息队列中消息大小支持是1个,2个,4个,8个和16个32位字,一个消息队列消息大小只能是其中一种,在创建消息队列时指定。
    一般消息内容比较多时,使用指针来传递。创建一个消息大小为一个字的队列,存储传递的指针,线程发送或接受消息指针,而不是整个消息。
    消息队列中存储消息个数有消息大小和分配的存储空间大小决定。消息个数=存储空间字节数/单个消息字节数。
    存储空间由应用开发人员分配好,是在消息创建时把存储空间地址作为入参。这块存储空间可以指定在高速ram中,提供系统性能。

    消息队列控制块

    消息队列控制块(QCB)是用来保持运行时消息队列状态的数据结构。

    typedef struct TX_QUEUE_STRUCT
    {
    
        /* Define the queue ID used for error checking.  */
        ULONG       tx_queue_id;
    
        /* Define the queue's name.  */
        CHAR_PTR    tx_queue_name;
    
        /* Define the message size that was specified in queue creation.  */
        UINT        tx_queue_message_size;
    
        /* Define the total number of messages in the queue.  */
        ULONG       tx_queue_capacity;
    
        /* Define the current number of messages enqueue and the available
           queue storage space.  */
        ULONG       tx_queue_enqueued;
        ULONG       tx_queue_available_storage;
    
        /* Define pointers that represent the start and end for the queue's
           message area.  */
        ULONG_PTR   tx_queue_start;
        ULONG_PTR   tx_queue_end;
    
        /* Define the queue read and write pointers.  Send requests use the write
           pointer while receive requests use the read pointer.  */
        ULONG_PTR   tx_queue_read;
        ULONG_PTR   tx_queue_write;
    
        /* Define the queue suspension list head along with a count of
           how many threads are suspended.  */
        struct TX_THREAD_STRUCT  *tx_queue_suspension_list;
        ULONG                    tx_queue_suspended_count;
    
        /* Define the created list next and previous pointers.  */
        struct TX_QUEUE_STRUCT
            *tx_queue_created_next,
            *tx_queue_created_previous;
    
    } TX_QUEUE;
    
    意义
    tx_queue_id队列id标志
    tx_queue_name队列名字,创建者指定
    tx_queue_message_size消息大小
    tx_queue_capacity队列容量(消息个数最大值)
    tx_queue_enqueued
    tx_queue_available_storage队列中可用存储空间
    tx_queue_start指向消息队列头部指针
    tx_queue_end指向消息队列尾部指针
    tx_queue_read读指针,指向消息队列中第一个可读消息地址
    tx_queue_write写指针,指向消息队列中第一个可写消息地址
    tx_queue_suspension_list挂起队列指针,挂起读线程或发送线程
    tx_queue_suspended_count挂起队列中线程个数
    tx_queue_created_next指向下一个消息队列指针
    tx_queue_created_previous指向前一个消息队列指针

    消息队列list

    系统中所有信号量控制块挂载一个双向链表_tx_queue_created_ptr中,tx_queue_created_next指向下一个消息队列指针,tx_queue_created_previous指向前一个消息队列指针。

    在这里插入图片描述

    消息队列API

    函数描述
    _tx_queue_create创建消息队列
    _tx_queue_delete删除消息队列
    _tx_queue_flush清空消息队列中消息或挂起队列中线程
    _tx_queue_info_get获取消息队列信息
    _tx_queue_receive读取消息队列消息
    _tx_queue_send发送消息到队列尾部
    _tx_queue_front_send发送消息到队列头部
    _tx_queue_prioritize调整挂起队列头部为最高优先级线程

    创建消息队列_tx_queue_create

    message_size当个消息占用几个 32位字
    queue_start消息队列存储空间首地址
    queue_size存储空间大小

    UINT    _tx_queue_create(TX_QUEUE *queue_ptr, CHAR *name_ptr, UINT message_size,
                             VOID *queue_start, ULONG queue_size)
    {
    
        TX_INTERRUPT_SAVE_AREA
    
        TX_QUEUE    *tail_ptr;                      /* Working queue pointer     */
        REG_1 UINT  capacity;                       /* Queue's message capacity  */
        REG_2 UINT  used_words;                     /* Number of words used      */
    
    
        /* Setup the basic queue fields.  */
        queue_ptr -> tx_queue_name =             name_ptr;
        queue_ptr -> tx_queue_suspension_list =  TX_NULL;
        queue_ptr -> tx_queue_suspended_count =  0;
    
        /* Save the message size in the control block.  */
        queue_ptr -> tx_queue_message_size =  message_size;
    
        /* Determine how many messages will fit in the queue area and the number
           of ULONGs used.  */
        #def 计算消息队列容量,message_size表示占用几个sizeof(ULONG),queue_size 表示总空间大小(字节),容量为总的空间字节/单个消息字节,capacity存储了计算后消息队列能够存储消息个数,used_words 为消息队列容量,单位是字节
        if (message_size == TX_1_ULONG)
        {
            capacity =  queue_size / (TX_1_ULONG * sizeof(ULONG));
            used_words =  capacity;
        }
        else if (message_size == TX_2_ULONG)
        {
            capacity =  queue_size / (TX_2_ULONG * sizeof(ULONG));
            used_words =  capacity * TX_2_ULONG;
        }
        else if (message_size == TX_4_ULONG)
        {
            capacity =  queue_size / (TX_4_ULONG * sizeof(ULONG));
            used_words =  capacity * TX_4_ULONG;
        }
        else if (message_size == TX_8_ULONG)
        {
            capacity =  queue_size / (TX_8_ULONG * sizeof(ULONG));
            used_words =  capacity * TX_8_ULONG;
        }
        else
        {
            capacity =  queue_size / (TX_16_ULONG * sizeof(ULONG));
            used_words =  capacity * TX_16_ULONG;
        }
    
        /* Save the starting address and calculate the ending address of
           the queue.  Note that the ending address is really one past the
           end!  */
           #def 设置消息队列存储空间起始地址和终止地址
        queue_ptr -> tx_queue_start = (ULONG_PTR) queue_start;
        queue_ptr -> tx_queue_end = ((ULONG_PTR) queue_start) + used_words;
    
        /* Set the read and write pointers to the beginning of the queue
           area.  */
          #def 初始消息队列读写指针为存储空间起始地址
        queue_ptr -> tx_queue_read = (ULONG_PTR) queue_start;
        queue_ptr -> tx_queue_write = (ULONG_PTR) queue_start;
    
        /* Setup the number of enqueued messages and the number of message
           slots available in the queue.  */
        #def 初始空间容量和当前消息个数,剩余空间(单位都是消息个数,不是字节)
        queue_ptr -> tx_queue_enqueued =           0;
        queue_ptr -> tx_queue_available_storage =  capacity;
        queue_ptr -> tx_queue_capacity =           capacity;
    
        /* Disable interrupts to put the queue on the created list.  */
        #def 禁止中断,也就是禁止中断处理或其他线程打断本线程。处理全局变量
        TX_DISABLE
    
        /* Setup the queue ID to make it valid.  */
        #def 表示消息队列有效标志
        queue_ptr -> tx_queue_id =  TX_QUEUE_ID;
    
        /* Place the queue on the list of created queues.  First,
           check for an empty list.  */
           #def 插入_tx_queue_created_ptr list
        if (_tx_queue_created_ptr)
        {
    
            /* Pickup tail pointer.  */
            tail_ptr =  _tx_queue_created_ptr -> tx_queue_created_previous;
    
            /* Place the new queue in the list.  */
            _tx_queue_created_ptr -> tx_queue_created_previous =  queue_ptr;
            tail_ptr -> tx_queue_created_next =  queue_ptr;
    
            /* Setup this queues's created links.  */
            queue_ptr -> tx_queue_created_previous =  tail_ptr;
            queue_ptr -> tx_queue_created_next =      _tx_queue_created_ptr;
        }
        else
        {
    
            /* The created queue list is empty.  Add queue to empty list.  */
            _tx_queue_created_ptr =                   queue_ptr;
            queue_ptr -> tx_queue_created_next =      queue_ptr;
            queue_ptr -> tx_queue_created_previous =  queue_ptr;
        }
    
        /* Increment the number of queues created counter.  */
        _tx_queue_created_count++;
    
        /* Restore interrupts.  */
        TX_RESTORE
    
        /* Return TX_SUCCESS.  */
        return (TX_SUCCESS);
    }
    

    删除队列_tx_queue_delete

    UINT    _tx_queue_delete(TX_QUEUE *queue_ptr)
    {
    
        TX_INTERRUPT_SAVE_AREA
    
        TX_THREAD       *thread_ptr;                /* Working thread pointer  */
    
    
        /* Disable interrupts to remove the queue from the created list.  */
        #def 禁止中断,防止处理被打断,处理全局变量
        TX_DISABLE
    
        /* Decrement the number of queues created.  */
        _tx_queue_created_count--;
    
        /* Clear the queue ID to make it invalid.  */
        #def 标记为无效
        queue_ptr -> tx_queue_id =  0;
    
        /* See if the queue is the only one on the list.  */
        #def 从_tx_queue_created_ptr 链表中删除
        if (queue_ptr == queue_ptr -> tx_queue_created_next)
        {
    
            /* Only created queue, just set the created list to NULL.  */
            _tx_queue_created_ptr =  TX_NULL;
        }
        else
        {
    
            /* Link-up the neighbors.  */
            (queue_ptr -> tx_queue_created_next) -> tx_queue_created_previous =
                queue_ptr -> tx_queue_created_previous;
            (queue_ptr -> tx_queue_created_previous) -> tx_queue_created_next =
                queue_ptr -> tx_queue_created_next;
    
            /* See if we have to update the created list head pointer.  */
            if (_tx_queue_created_ptr == queue_ptr)
    
                /* Yes, move the head pointer to the next link. */
                _tx_queue_created_ptr =  queue_ptr -> tx_queue_created_next;
        }
    
    	#def 先禁止线程抢占,然后TX_RESTORE开中断,之后处理可以被中断打断,减少中断处理时延,但不能被高优先级抢占,因为高优先级可能使用这个队列
        /* Temporarily disable preemption.  */
        _tx_thread_preempt_disable++;
    
        /* Restore interrupts.  */
        TX_RESTORE
    
        /* Walk through the queue list to resume any and all threads suspended
           on this queue.  */
        #def 清除挂起链表中线程,恢复线程
        thread_ptr =  queue_ptr -> tx_queue_suspension_list;
        while (queue_ptr -> tx_queue_suspended_count)
        {
            /* Lockout interrupts.  */
            TX_DISABLE
    
            /* Clear the cleanup pointer, this prevents the timeout from doing
               anything.  */
            thread_ptr -> tx_suspend_cleanup =  TX_NULL;
    
            /* Temporarily disable preemption again.  */
            _tx_thread_preempt_disable++;
    
            /* Restore interrupts.  */
            TX_RESTORE
    
            /* Yes, deactivate the thread's timer just in case.  */
            _tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));
    
            /* Clear the remaining time to ensure timer doesn't get activated.  */
            thread_ptr -> tx_thread_timer.tx_remaining_ticks =  0;
    
            /* Set the return status in the thread to TX_DELETED.  */
            thread_ptr -> tx_suspend_status =  TX_DELETED;
    
            /* Move the thread pointer ahead.  */
            thread_ptr =  thread_ptr -> tx_suspended_next;
    
            /* Resume the thread.  */
            _tx_thread_resume(thread_ptr -> tx_suspended_previous);
    
            /* Decrease the suspended count.  */
            queue_ptr -> tx_queue_suspended_count--;
        }
    
    	#def 禁止中断,为了操作_tx_thread_preempt_disable,开启抢占
        /* Disable interrupts.  */
        TX_DISABLE
    
        /* Release previous preempt disable.  */
        _tx_thread_preempt_disable--;
    
        /* Restore interrupts.  */
        TX_RESTORE
    
        /* Check for preemption.  */
        #def 前面已经恢复了线程,可能有高优先级线程需要调度
        if (_tx_thread_current_ptr != _tx_thread_execute_ptr)
    
            /* Transfer control to system.  */
            #def 线程切换
            _tx_thread_system_return();
    
        /* Return TX_SUCCESS.  */
        return (TX_SUCCESS);
    }
    

    清空消息队列_tx_queue_flush

    _tx_queue_flush函数清空消息队列中消息,挂起线程,设置为初始化状态。

    UINT    _tx_queue_flush(TX_QUEUE *queue_ptr)
    {
    
        TX_INTERRUPT_SAVE_AREA
    
        TX_THREAD       *suspension_list;           /* Pickup the suspension list head  */
        UINT            suspended_count;            /* Count of suspended threads       */
        TX_THREAD       *thread_ptr;                /* Working thread pointer           */
    
    
        /* Initialize the suspended count.  */
        suspended_count =  0;
    
        /* Disable interrupts to reset various queue parameters.  */
        #def 禁止中断,下面操作全局变量,防止被打断,被抢占
        TX_DISABLE
    
        /* Determine if there is something on the queue.  */
        #def 如果队列不为空,清除消息,恢复初始化值
        if (queue_ptr -> tx_queue_enqueued)
        {
    
            /* Yes, there is something in the queue.  */
    
            /* Reset the queue parameters to erase all of the queued messages.  */
            #def 设置为空,初始化
            queue_ptr -> tx_queue_enqueued =           0;
            queue_ptr -> tx_queue_available_storage =  queue_ptr -> tx_queue_capacity;
            queue_ptr -> tx_queue_read =               queue_ptr -> tx_queue_start;
            queue_ptr -> tx_queue_write =              queue_ptr -> tx_queue_start;
    
            /* Now determine if there are any threads suspended on a full queue.  */
            #def 如果有挂起的线程,删除list中线程,并恢复线程状态
            if (queue_ptr -> tx_queue_suspended_count)
            {
    
                /* Yes, there are threads suspended on this queue, they must be
                   resumed!  */
    
                /* Copy the information into temporary variables.  */
                suspension_list =  queue_ptr -> tx_queue_suspension_list;
                suspended_count =  queue_ptr -> tx_queue_suspended_count;
    
                /* Clear the queue variables.  */
                queue_ptr -> tx_queue_suspension_list =  TX_NULL;
                queue_ptr -> tx_queue_suspended_count =  0;
    
                /* Temporarily disable preemption.  */
                #def 禁止抢占
                _tx_thread_preempt_disable++;
            }
        }
    
        /* Restore interrupts.  */
        TX_RESTORE
    
        /* Walk through the queue list to resume any and all threads suspended
           on this queue.  */
         #def 恢复线程
        if (suspended_count)
        {
    
            /* Pickup the thread to resume.  */
            thread_ptr =  suspension_list;
            do
            {
    
                /* Resume the next suspended thread.  */
    
                /* Lockout interrupts.  */
                TX_DISABLE
    
                /* Clear the cleanup pointer, this prevents the timeout from doing
                   anything.  */
                thread_ptr -> tx_suspend_cleanup =  TX_NULL;
    
                /* Temporarily disable preemption again.  */
                _tx_thread_preempt_disable++;
    
                /* Restore interrupts.  */
                TX_RESTORE
    
                /* Yes, deactivate the thread's timer just in case.  */
                _tx_timer_deactivate(&(thread_ptr -> tx_thread_timer));
    
                /* Clear the remaining time to ensure timer doesn't get activated.  */
                thread_ptr -> tx_thread_timer.tx_remaining_ticks =  0;
    
                /* Set the return status in the thread to TX_SUCCESS.  */
                thread_ptr -> tx_suspend_status =  TX_SUCCESS;
    
                /* Move the thread pointer ahead.  */
                thread_ptr =  thread_ptr -> tx_suspended_next;
    
                /* Resume the thread.  */
                _tx_thread_resume(thread_ptr -> tx_suspended_previous);
    
                /* Continue while there are suspended threads.  */
            }
            while (--suspended_count);
    
            /* Disable interrupts.  */
            TX_DISABLE
    
            /* Restore previous preempt posture.  */
            _tx_thread_preempt_disable--;
    
            /* Restore interrupts.  */
            TX_RESTORE
    
            /* Check for preemption.  */
            #def 恢复线程或中断后,可能有高优先级线程,进行调度切换
            if (_tx_thread_current_ptr != _tx_thread_execute_ptr)
    
                /* Transfer control to system.  */
                _tx_thread_system_return();
        }
    
        /* Return TX_SUCCESS.  */
        return (TX_SUCCESS);
    }
    

    参考:嵌入式实时操作系统的多线程计算

    展开全文
  • python 队列(queue)阻塞

    千次阅读 2021-01-14 20:46:57
    背景:python队列 queue.Queue或 multiprcessing.Queue 或其他队列在写入队列或从队列中读取元素时,都有可能会发生线程阻塞。下面来说一下阻塞的类型,然后怎么避免阻塞~一、阻塞的类型队列的阻塞分为:入队(put)时...
  • C语言实现的队列Queue

    热门讨论 2013-01-16 04:20:05
    数据结构Queue的实现在queue.h中, testQ为queue的用法
  • Java Queue offer()用法及代码示例

    千次阅读 2021-04-17 05:15:38
    } } 输出: The Queue is not full and 10 is inserted The Queue is not full and 15 is inserted The Queue is not full and 25 is inserted The Queue is full Queue:[10, 15, 25] 程序2:借助...
  • delphi中关于队列的使用QUEUE

    热门讨论 2013-03-28 17:32:22
    delphi中关于队列的使用QUEUE,已在delphi7中调试通过。 学习queue的小例子。
  • Python -- Queue模块

    千次阅读 2021-01-28 18:17:58
    Queue模块定义了以下类及异常,在队列类中,maxsize限制可入队列数据的数量,值小于等于0时代表不限制: Queue.Queue(maxsize=0) FIFO队列 Queue.LifoQueue(maxsize=0) LIFO队列 Queue.PriorityQueue(maxsize=0) ...
  • 【完美解决】SpringBoot整合rabbitmq "Failed to declare queue(s)
  • 廖雪峰Java5Java集合-5Queue-1使用Queue

    千次阅读 2021-03-16 10:57:20
    Queue特性和基本方法Queue实现一个先进先出(FIFO, First In First Out)的队列。如收银台排队支付。Java中LinkedList实现了Queue接口,可以直接把LinkedList当作Queue来使用。获取队列长度size()添加元素到队尾...
  • STL中的三大容器适配器:stack、queue、priority_queue。 一:deque(双端队列) 在学习容器适配器之前我们首先了解一个叫做deque的序列容器。 deque(双端队列): 是一个双端操作,任意位置O(1)插
  • C++队列queue用法详解

    万次阅读 多人点赞 2020-11-17 16:13:42
    C++队列queue用法详解一、定义一、queue初始化初始化示例注意:不能用vector容器初始化queue二、queue常用函数1.常用函数2.函数运用示例 一、定义 queue是一种容器转换器模板,调用#include< queue>即可使用...
  • queue模块是提供队列操作的模块,虽然简单易用,但是不小心的话,还是会出现一些意外。 1. 阻塞模式 q = queue.Queue(10) #创建一个队列 ...... for i in range(10): q.put('A') time.sleep(0.5) 这是一...
  • Queue.Queue是进程内非阻塞队列,multiprocess.Queue是跨进程通信队列。 2、区别 1.from queue import Queue 这个是普通的队列模式,类似于普通列表,先进先出模式,get方法会阻塞请求,直到有数据get出来为止 2...
  • C++ queue队列如何遍历

    千次阅读 2021-09-08 14:49:37
    queue是先进后出的数据类型,只能不断读top()然后再pop()掉。故意把遍历操作隐藏掉了,因为如果要遍历就不该用queue。 #include<iostream> #include<queue> using namespace std; int main(int...
  • python模块之Queue

    万次阅读 多人点赞 2019-06-13 21:03:04
    myqueue = Queue.Queue(maxsize = 10) Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。 将一个值放...
  • C++中queue使用详细说明

    千次阅读 多人点赞 2021-03-30 17:21:43
    一、queue的介绍 queue 翻译为队列,在 STL 中主要则是实现了一个先进先出的容器。 二、queue的定义 单独定义一个 queuequeue<typename> name; //这里的typename可以是任何基本类型,例如 int、...
  • 在本文中,我们将讨论C ++ STL中queue::front()和queue::back()函数的工作,语法和示例。C ++ STL中的队列是什么?队列是C ++ STL中定义的简单序列或数据结构,它以FIFO(先进先出)的方式插入和删除数据。队列中的...
  • php think queue:listen --queue 开启长连接: sudo -u www php think workerman start --d 开启定时任务: php think timer start --d 删除下列函数 proc_open pcntl_signal pcntl_signal_dispatch pcntl_fork ...
  • Python分布式进程使用(Queue和BaseManager使用)

    千次阅读 多人点赞 2019-03-03 21:39:05
    分布式进程 需要模块 multiprocessing和queue模块 使用BaseManager创建分布式管理器 使用Queue创建队列,用于多个进程之间的...比如爬取图片:一般一个进程负责抓取图片的地址,将地址放在Queue(容器)队列...
  • 第十章第十题(Queue类)(Queue class) *10.10(Queue类)10.6节给出了一个Stack类。设计一个名为Queue的类用于存储整数。像栈一样,队列保存元素。在栈中,元素以“后进先出”的方式获取。在队列中,元素以...
  • C++优先队列priority_queue详解

    千次阅读 2021-12-14 13:17:31
    priority_queue也是在写算法中很厉害且常用的一种数据结构,本文详细介绍了C++ STL中的使用方法~
  • Python多进程队列Queue

    千次阅读 2021-02-27 19:08:30
    Queue是python多进程的安全队列,可以使用Queue实现多进程之间的数据传递。 示例: from multiprocessing import Process, Queue import time def ProducerA(q): count = 1 while True: q.put(f"冷饮 {count...
  • Python Queue模块详解

    千次阅读 2020-12-04 13:38:29
    创建一个“队列”对象import queueq = queue.queue(maxsize = 10)queue.queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过queue的构造函数的可选参数maxsize来设定队列长度。如果maxsi...
  • ROS queue_size和buff_size设置

    千次阅读 2021-12-01 10:41:33
    通过设置queue_size和buff_size提高ROS话题订阅实时性
  • Java中队列(Queue)用法

    千次阅读 2022-03-02 20:49:10
    Java中队列queue的用法 数据结构 队列
  • C++ queue常见用法详解

    千次阅读 2021-05-03 11:03:07
    queue> 队列:“先进先出”,即只能在容器的末尾添加新元素,只能从头部移除元素。 queue 的生成方式和 stack 相同: queue<typename> name; queue 容器内元素的访问:只能通过front()来访问队首元素,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,446,451
精华内容 578,580
关键字:

queue