精华内容
下载资源
问答
  • TCP套接口的最大SYN队列长度

    千次阅读 2019-02-19 14:58:00
    通过PROC文件查看队列长度,可见对于4G内存的系统,tcp_max_syn_backlog的值为128;对于8G内存的系统,其值为256。 # cat /proc/sys/net/ipv4/tcp_max_syn_backlog 128 # / # cat /proc/sys/...

    通过PROC文件查看队列长度,可见对于4G内存的系统,tcp_max_syn_backlog的值为128;对于8G内存的系统,其值为256。

    # cat /proc/sys/net/ipv4/tcp_max_syn_backlog
    128
    # 
    / # cat /proc/sys/net/ipv4/tcp_max_syn_backlog 
    256

    PROC文件tcp_max_syn_backlog控制处在TCP_SYN_RECV状态的TCP连接最大数,默认值为128。即接收到SYN报文并且已发送SYN+ACK但还未收到对端ACK响应的连接最大数,此数值为基于单个socket的控制。128为最小值,对于内存较大的机器,可适当调高此值。PROC文件变量定义如下:

    static struct ctl_table ipv4_net_table[] = { 
        {
            .procname   = "tcp_max_syn_backlog",
            .data       = &init_net.ipv4.sysctl_max_syn_backlog,
        },
    }

    队列长度初始化

    在函数tcp_sk_init中,初始化sysctl_max_syn_backlog,赋值为128与cnt的256分之一两个值之间的最大值。

    static int __net_init tcp_sk_init(struct net *net)
    {
        cnt = tcp_hashinfo.ehash_mask + 1;
        net->ipv4.sysctl_max_syn_backlog = max(128, cnt / 256);
    }

    其中cnt的值由tcp_hashinfo.ehash_mask决定,其在tcp_init函数中初始化。ehash_mask哈希掩码值为inet_ehash_bucket类型哈希表最大表项值减1,此处hash表的表项数值为2的幂值,其减一得到的掩码为一个全F的值。

    void __init tcp_init(void)
    {
        tcp_hashinfo.ehash =
            alloc_large_system_hash("TCP established",
                        sizeof(struct inet_ehash_bucket),
                        thash_entries,
                        17, /* one slot per 128 KB of memory */
                        0,
                        NULL,
                        &tcp_hashinfo.ehash_mask,
                        0,
                        thash_entries ? 0 : 512 * 1024);
    }

    需要注意的是tcp_hashinfo.ehash不仅包括已建立连接的TCP套接口,还包括除了在LISTEN状态的其它所有套接口。

    /* This is for all connections with a full identity, no wildcards.
     * The 'e' prefix stands for Establish, but we really put all sockets
     * but LISTEN ones.
     */
    struct inet_ehash_bucket {
        struct hlist_nulls_head chain;
    };

    队列长度判断逻辑
     

    参见tcp_conn_request函数中的判断条件,在SYN Cookies功能未开启,并且当前请求套接口的队列长度(inet_csk_reqsk_queue_len)已经超过最大SYN队列长度值(sysctl_max_syn_backlog)的3/4后,仅接收已知客户端的SYN连接(tcp_peer_is_proven)。意味着最后1/4的额度保留给了最近连接过的客户端,未连接过的客户端在到达最大值的3/4后,就已经不能接入了。

    int tcp_conn_request(struct request_sock_ops *rsk_ops, const struct tcp_request_sock_ops *af_ops, struct sock *sk, struct sk_buff *skb)
    {
        __u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn;
        bool want_cookie = false;
    
        if (!want_cookie && !isn) {
            if (!net->ipv4.sysctl_tcp_syncookies &&
                (net->ipv4.sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < (net->ipv4.sysctl_max_syn_backlog >> 2)) &&
                !tcp_peer_is_proven(req, dst)) {
                goto drop_and_release;
            }
        }
    }

    如果开启了TCP的SYN cookies功能并且检测到SYN flood行为,又或者SYN请求对应到一个之前处于TIME-WAIT状态的套接口,此两种情况不对新连接做SYN队列超限判断。


    内核版本 Linux-4.15

     

    展开全文
  • 多线程之Disruptor高性能内存队列 消息队列容器 Disruptor的特点 Disruptor是数组实现的 无锁,高并发,使用环形Buffer,直接覆盖(不用清除)旧的数据,降低GC频率 实现了基于事件的生产者消费者模式(观察者模式...

    多线程之Disruptor高性能内存队列

    消息队列容器

    Disruptor的特点

    1. Disruptor是数组实现的
    2. 无锁,高并发,使用环形Buffer,直接覆盖(不用清除)旧的数据,降低GC频率
    3. 实现了基于事件的生产者消费者模式(观察者模式)

    RingBuffer

    环形队列

    RingBuffer的序号,指向下一个可用的元素

    采用数组实现,没有首尾指针

    对比ConcurrentLinkedQueue,用数组实现的速度更快

    原素定位

    假如长度为8,当添加到第12个元素的时候在哪个序号上呢?用12%8决定

    当Buffer被填满的时候到底是覆盖还是等待,由Producer决定

    长度设为2的n次幂,利于二进制计算,例如:12%8 = 12 & (8 - 1) pos = num & (size -1)

    使用

    1. 添加依赖
    <dependency>
        <groupId>com.lmax</groupId>
        <artifactId>disruptor</artifactId>
        <version>3.4.2</version>
    </dependency>
    
    1. 定义Event - 队列中需要处理的元素

    2. 定义Event工厂,用于填充队列

      implements EventFactory

      使用工厂模式,这里牵扯到效率问题:disruptor初始化的时候,会调用Event工厂,对ringBuffer进行内存的提前分配

      GC产生频率会降低

    3. 定义EventHandler(消费者),处理容器中的元素,实现onEvent方法

    public class LongEventHandler implements EventHandler<LongEvent> 
    
    1. 定义生产者
    public class LongEventProducer {
        private final RingBuffer<LongEvent> ringBuffer;
    
        public LongEventProducer(RingBuffer<LongEvent> ringBuffer) {
            this.ringBuffer = ringBuffer;
        }
    
        public void onData(ByteBuffer buffer) {
            // 获取下一个位置
            long sequence = ringBuffer.next();
            try {
                // 设置内容
                LongEvent event = ringBuffer.get(sequence);
                event.setValue(buffer.getLong(0));
            } finally {
                // 发布信息
                ringBuffer.publish(sequence);
            }
        }
    
    }
    
    1. 运行流程
        public static void main(String[] args) {
            //Executor executor = Executors.newCachedThreadPool();
    
            LongEventFactory factory = new LongEventFactory();
    
            //must be power of 2
            int ringBufferSize = 1024;
    //  初始化
            Disruptor<LongEvent> disruptor = new Disruptor<LongEvent>(factory, ringBufferSize, Executors.defaultThreadFactory());
    // 设置处理类
            disruptor.handleEventsWith(new LongEventHandler());
    // 启动容器
            disruptor.start();
    
            RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
    
            LongEventProducer producer = new LongEventProducer(ringBuffer);
    
            ByteBuffer bb = ByteBuffer.allocate(8);
    
            for(long l = 0; l<100; l++) {
                bb.putLong(0, l);
    
                producer.onData(bb);
    
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            disruptor.shutdown();
        }
    

    第二种生产者写法

    public class LongEventProducer {
        private final RingBuffer<LongEvent> ringBuffer;
        // 将数据转换为Event对象
        private static final EventTranslatorOneArg<LongEvent, ByteBuffer> TRANSLATOR = new EventTranslatorOneArg<LongEvent, ByteBuffer>() {
            @Override
            public void translateTo(LongEvent event, long sequence, ByteBuffer bb) {
                event.setValue(bb.getLong(0));
            }
        };
    
        public LongEventProducer(RingBuffer<LongEvent> ringBuffer) {
            this.ringBuffer = ringBuffer;
        }
    
        public void onData(ByteBuffer buffer) {
            //发布时间
            ringBuffer.publishEvent(TRANSLATOR, buffer);
        }
    
    }
    
    

    lamda表达式写法,

    定义事件类,无需在写工厂类,生产者消费者类了。

       public static void main(String[] args) {
            int bufferSize = 1024;
    
            // 构造容器
            // Construct the Disruptor
            Disruptor<LongEvent> disruptor = new Disruptor<>(LongEvent::new, bufferSize, DaemonThreadFactory.INSTANCE);
            // 添加消费方法
            // Connect the handler
            disruptor.handleEventsWith((event, sequence, endOfBatch) -> System.out.println(event.getValue()));
            // 启动容器
            // Start the Disruptor, starts all threads running
            disruptor.start();
    
            // Get the ring buffer from the Disruptor to be used for publishing.
            RingBuffer<LongEvent> ringBuffer = disruptor.getRingBuffer();
    
            ByteBuffer bb = ByteBuffer.allocate(8);
            for (long l = 0; true; l++)
            {
                bb.putLong(0, l);
                // 发布消息
                ringBuffer.publishEvent((event, sequence, buffer) -> event.setValue(buffer.getLong(0)), bb);
    
               
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    

    ProducerType生产者线程模式

    ProducerType有两种模式 Producer.MULTI和Producer.SINGLE

    默认是MULTI,表示在多线程模式下产生sequence

    如果确认是单线程生产者,那么可以指定SINGLE,效率会提升

    如果是多个生产者(多线程),但模式指定为SINGLE,会出什么问题呢?
    消息会丢失。

    等待策略

    1,(常用)BlockingWaitStrategy:通过线程阻塞的方式,等待生产者唤醒,被唤醒后,再循环检查依赖的sequence是否已经消费。

    2,BusySpinWaitStrategy:线程一直自旋等待,可能比较耗cpu

    3,LiteBlockingWaitStrategy:线程阻塞等待生产者唤醒,与BlockingWaitStrategy相比,区别在signalNeeded.getAndSet,如果两个线程同时访问一个访问waitfor,一个访问signalAll时,可以减少lock加锁次数.

    4,LiteTimeoutBlockingWaitStrategy:与LiteBlockingWaitStrategy相比,设置了阻塞时间,超过时间后抛异常。

    5,PhasedBackoffWaitStrategy:根据时间参数和传入的等待策略来决定使用哪种等待策略

    6,TimeoutBlockingWaitStrategy:相对于BlockingWaitStrategy来说,设置了等待时间,超过后抛异常

    7,(常用)YieldingWaitStrategy:尝试100次,然后Thread.yield()让出cpu

    1. (常用)SleepingWaitStrategy : sleep

    消费者异常处理

    默认:disruptor.setDefaultExceptionHandler()

    覆盖:disruptor.handleExceptionFor().with()

    源码分析

    设计思路

    https://tech.meituan.com/2016/11/18/disruptor.html

    Disruptor通过以下设计来解决队列速度慢的问题:

    1. 环形数组结构

    为了避免垃圾回收,采用数组而非链表。同时,数组对处理器的缓存机制更加友好。

    1. 元素位置定位

    数组长度2^n,通过位运算,加快定位的速度。下标采取递增的形式。不用担心index溢出的问题。index是long类型,即使100万QPS的处理速度,也需要30万年才能用完。

    1. 无锁设计

    先申请 再写入
    每个生产者或者消费者线程,会先申请可以操作的元素在数组中的位置,申请到之后,直接在该位置写入或者读取数据。整个过程通过原子变量CAS,保证操作的线程安全

    写入情况设计

    单线程
    多线程情况下:

    Disruptor在多个生产者的情况下,引入了一个与Ring Buffer大小相同的buffer:available Buffer。当某个位置写入成功的时候,便把availble Buffer相应的位置置位,标记为写入成功。读取的时候,会遍历available Buffer,来判断元素是否已经就绪。

    核心类介绍

    1. RingBuffer 环状队列

    属性

    1. Sequence类

    跟踪环形缓冲区和事件处理器的进度。

    提供了一个long型的来记录,使用volatile修饰,同时对他的操作都是cas 操作的

    class LhsPadding{
        protected long p1, p2, p3, p4, p5, p6, p7;
    }
    
    class Value extends LhsPadding
    {
        protected volatile long value;
    }
    
    class RhsPadding extends Value
    {
        protected long p9, p10, p11, p12, p13, p14, p15;
    }
    
    public class Sequence extends RhsPadding{
        
    }
    

    相关属性

    // 存储数据的环状数组
    private final RingBuffer<T> ringBuffer;
    private final Executor executor;
    // 消费者注册
    private final ConsumerRepository<T> consumerRepository = new ConsumerRepository<>();
    // 开始状态
    private final AtomicBoolean started = new AtomicBoolean(false);
    // 异常处理器
    private ExceptionHandler<? super T> exceptionHandler = new ExceptionHandlerWrapper<>();
    

    构造器

    参数说明

    eventFactory :在环形缓冲区中创建事件的工厂。

    ringBufferSize :环形缓冲区的大小,必须是2的幂。

    threadFactory 为处理器创建线程的工厂。

    producerType 生产者模式,是SINGLE、MULTI。

    waitStrategy 用于环形缓冲区的等待策略。

        public Disruptor(
                final EventFactory<T> eventFactory,
                final int ringBufferSize,
                final ThreadFactory threadFactory,
                final ProducerType producerType,
                final WaitStrategy waitStrategy)
        {
            this(
                RingBuffer.create(producerType, eventFactory, ringBufferSize, waitStrategy),
                new BasicExecutor(threadFactory));
        }
    

    设置处理器池WorkerPool

    容器会将事件分发到工作处理程序线程池中的一个进行处理

    每个事件都只有一个处理器进行处理

    当容器start时,会自动启动workerPool处理

    @SafeVarargs
    @SuppressWarnings("varargs")
    public final EventHandlerGroup<T> handleEventsWithWorkerPool(final WorkHandler<T>... workHandlers){
        return createWorkerPool(new Sequence[0], workHandlers);
    }
    
    /**
    * 创建workerPool
    */
    EventHandlerGroup<T> createWorkerPool(
        final Sequence[] barrierSequences, final WorkHandler<? super T>[] workHandlers){
        // 
        final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(barrierSequences);
        final WorkerPool<T> workerPool = new WorkerPool<>(ringBuffer, sequenceBarrier, exceptionHandler, workHandlers);
    
    
        consumerRepository.add(workerPool, sequenceBarrier);
    
        final Sequence[] workerSequences = workerPool.getWorkerSequences();
    
        updateGatingSequencesForNextInChain(barrierSequences, workerSequences);
    
        return new EventHandlerGroup<>(this, consumerRepository, workerSequences);
    }
    
    展开全文
  • zeromq里面关这个对垒长度限制叫做 “High Water Marks”,2.0版本默认是没有限制的,3.0里面这个长度默认为1000。这个比较容易达到啊,根据包大小和消耗的内存大概修改一下才行。 zeromq的api也提供了修改系统的tcp...

    zeromq里面关这个对垒长度限制叫做 “High Water Marks”,2.0版本默认是没有限制的,3.0里面这个长度默认为1000。这个比较容易达到啊,根据包大小和消耗的内存大概修改一下才行。 zeromq的api也提供了修改系统的tcp缓存大小的接口了。

    详细的socket选项,参考 http://api.zeromq.org/3-2:zmq-setsockopt
    https://www.cnblogs.com/fengbohello/p/4398953.html

    ZMQ_SNDHWM: Set high water mark for outbound messages
    ZMQ_RCVHWM: Set high water mark for inbound messages

    socket   =   new  zmq :: socket_t   (* context ,  ZMQ_PUSH );
    int  queue_length  =   5000 ;
    socket -> setsockopt ( ZMQ_SNDHWM ,   & queue_length , sizeof ( queue_length ));
    socket -> connect  ( "tcp://127.0.0.1:5555" ); 
    
    展开全文
  • /*** 使用共享内存的PHP循环内存队列实现* 支持多进程, 支持各种数据类型的存储* 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区* /class SHMQueue{private $maxQSize = 0; // 队列最大长度private $front =...

    /**

    * 使用共享内存的PHP循环内存队列实现

    * 支持多进程, 支持各种数据类型的存储

    * 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区

    * /

    class SHMQueue

    {

    private $maxQSize = 0; // 队列最大长度

    private $front = 0; // 队头指针

    private $rear = 0; // 队尾指针

    private $blockSize = 256; // 块的大小(byte)

    private $memSize = 25600; // 最大共享内存(byte)

    private $shmId = 0;

    private $filePtr = './shmq.ptr';

    private $semId = 0;

    public function __construct()

    {

    $shmkey = ftok(__FILE__, 't');

    $this->shmId = shmop_open($shmkey, "c", 0644, $this->memSize );

    $this->maxQSize = $this->memSize / $this->blockSize;

    // 申請一个信号量

    $this->semId = sem_get($shmkey, 1);

    sem_acquire($this->semId); // 申请进入临界区

    $this->init();

    }

    private function init()

    {

    if ( file_exists($this->filePtr) ){

    $contents = file_get_contents($this->filePtr);

    $data = explode( '|', $contents );

    if ( isset($data[0]) && isset($data[1])){

    $this->front = (int)$data[0];

    $this->rear = (int)$data[1];

    }

    }

    }

    public function getLength()

    {

    return (($this->rear - $this->front + $this->memSize) % ($this->memSize) )/$this->blockSize;

    }

    public function enQueue( $value )

    {

    if ( $this->ptrInc($this->rear) == $this->front ){ // 队满

    return false;

    }

    $data = $this->encode($value);

    shmop_write($this->shmId, $data, $this->rear );

    $this->rear = $this->ptrInc($this->rear);

    return true;

    }

    public function deQueue()

    {

    if ( $this->front == $this->rear ){ // 队空

    return false;

    }

    $value = shmop_read($this->shmId, $this->front, $this->blockSize-1);

    $this->front = $this->ptrInc($this->front);

    return $this->decode($value);

    }

    private function ptrInc( $ptr )

    {

    return ($ptr + $this->blockSize) % ($this->memSize);

    }

    private function encode( $value )

    {

    $data = serialize($value) . "__eof";

    if ( strlen($data) > $this->blockSize -1 ){

    throw new Exception(strlen($data)." is overload block size!");

    }

    return $data;

    }

    private function decode( $value )

    {

    $data = explode("__eof", $value);

    return unserialize($data[0]);

    }

    public function __destruct()

    {

    $data = $this->front . '|' . $this->rear;

    file_put_contents($this->filePtr, $data);

    sem_release($this->semId); // 出临界区, 释放信号量

    }

    }

    //*******************************************

    使用的样例代码如下:

    // 进队操作

    $shmq = new SHMQueue();

    $data = 'test data';

    $shmq->enQueue($data);

    unset($shmq);

    // 出队操作

    $shmq = new SHMQueue();

    $data = $shmq->deQueue();

    unset($shmq);

    ?>

    展开全文
  • /*** 使用共享内存的PHP循环内存队列实现* 支持多进程, 支持各种数据类型的存储* 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区** @author wangbinandi@gmail.com* @created 2009-12-23*/class SHMQueue{...
  • linux诡异的半连接(SYN_RECV)队列长度

    千次阅读 2013-08-27 11:18:26
    >>本文链接地址:linux诡异的半连接(SYN_RECV)队列长度(一) 最近在学习TCP方面的基础知识,对于古老的SYN Flood也有了更多认识。SYN Flood利用的是TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方...
  • 共享内存循环形队列池设计

    千次阅读 2016-12-01 10:47:44
    1、 简述 队列是一种先进先出(FIFO)的线性表数据结构,常见的操作如在表的尾部插入,在头部删除数据。队列的类型有链表结构、固定缓冲区结构等。常用的队列空间都是动态地... 队列长度计算公式:nCount = (rear - fr
  • SYN Flood利用的是TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。 SYN Flood的原理简单,实现也不复杂,而且网上有许多现成的程序。 我在两台虚拟机上...
  • 为了节省内存,写了一个固定内存不限长度队列,原理是最开始申请一片大的内存,后面队列使用的内存都从大内存中取得。解决了频繁申请内存的问题和控制队列使用内存大小的问题。 文件: ydzj_cloud_queue.h #ifndef ...
  • SYN Flood利用的是TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。 SYN Flood的原理简单,实现也不复杂,而且网上有许多现成的程序。 我在两台虚拟机上...
  • * 使用共享内存的PHP循环内存队列实现 * 支持多进程, 支持各种数据类型的存储 * 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区 * * @author wangbinandi@gmail.com * @created 2009-12-23 */ class ...
  • /*** 使用共享内存的PHP循环内存队列实现* 支持多进程, 支持各种数据类型的存储* 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区** @author wangbinandi@gmail.com* @created 2009-12-23*/class SHMQueue{...
  • FreeRTOS中的队列是非常关键的一个数据结构,是整个操作系统的消息处理的核心。...比较好的使用方式为将需要发送的数据放入一个自定义的结构体,然后malloc一块内存空间,将内存的首地址作为一个32bit的值...
  • 内存映射实现posix消息队列

    千次阅读 2013-10-04 16:56:21
    POSIX消息队列与System V消息队列的主要区别: 1.对POSIX队列的读总数返回最高优先级到最早消息,对SV队列到读则可以返回任意指定优先级的消息 2.当往一个空队列放置一个消息时,...2.消息的数据部分长度(可以为0)
  • 消息队列 消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识 1 #include <sys/msg.h> 2 // 创建或打开消息队列:成功返回队列...6 // 读取消息:成功返回消息数据的长度,失
  • 队列

    2020-06-07 21:40:04
    文章目录队列概述循环队列顺序存储实现链式结构存储 ...但这样又有问题了,我们数组是开辟了一片固定空间,队列长度应该是一定的,但是随着入队出队,可以认为队列再往后移动,可能会前面有一片内存空了出来
  • ·消息队列也具有管道的缺点,即每个消息的最大长度是有上限的,每个消息队列的总的字节数是有上限的,系统上消息队列的总数也有一个上限。 消息队列在内核中的表示 消息队列函数 1、创建和访问消息队列 ...
  • 消息队列的每块消息有最大长度的上限(MSGMAX),每个消息队列的总字节数也是有上限的(MSGMNB),系统上消息队列的总数也是有上限的(MSGMNI)。 内核为每个IPC对象维护一个结构体(struct ipc_perm),该结构存储了...
  • 初始状态的队列,队列长度为0,队头和队尾的指针相同均位于队列的开始;入队操作:队尾指针向后移动,长度加一;出队操作:队头指针向后移动,长度减一;循环队列特点:队列大小固定,队列所开辟的内存空间可循环...
  • 消息队列与命名管道一样,每个数据块都有一个最大长度的限制;我们可以将每个数据块当作是一中消息类型(频道),发送和接收的内容就是这个类型(频道)对应的消息(节目),每个类型(频道)相当于一个独立的管道,...
  • 这个周的Linux实验是做基于消息队列和共享内存的进程间通信,要求主要如下: 1)消息的创建、发送和接收 使用消息调用msgget()、msgsnd()、msggrev()msgctrl()编制长度为1K的消息的发送和接收程序。 2)共享...
  • 本节是《UNIX网络编程 卷2》 笔记 的最后一节,我们使用内存映射I/O实现Posix消息队列。之所以将这节内容放到最后是因为这个实现比较复杂,涵盖了之前讲述的很多内容。这个实现的具体思想和实现信号量类似:把消息...
  • \quad这个题目的是找出两个序列的中位数,给的内存为1.5M,单个序列大小为2∗1052*10^52∗105,int型。若将两个序列存储起来...设两个序列长度为num1,num2,那么排好序后中位数索引为mid=(num1+num2)/2mid=(num_1+n...
  • JAVA中数组、链表实现的队列的增加,返回长度,插入,删除   数组:   数组是java中最基本的一中数据结构,数组一旦定义,它的长度就是固定的。数组也是一种对象,数组的对象本身的类型就是数组类型。定义数组...
  • 循环队列

    2021-04-20 18:59:15
    循环队列,底层内存结构:静态数组 灵魂思想: 将指针的自增改为 指针 = (指针+ 1) % (数组的真实长度) // 循环队列 // 为了区分空队列和满队列 // 在这里我们认为当整个数组只剩下队尾的那块空间时,队列已满 // 当...
  • php实现队列

    2018-11-17 23:55:39
    初始状态的队列,队列长度为0,队头和队尾的指针相同均位于队列的开始; 入队操作:队尾指针向后移动,长度加一; 出队操作:队头指针向后移动,长度减一; 循环队列特点:队列大小固定,队列所开辟的内存空间可...
  • 预分配内存fifo实现可变长度字节序列存储 github链接https://github.com/gexin1023/utils/tree/master/fifo fifo即先进先出队列,可以用链表来实现,在链表头部插入数据,尾部读数据,每次插入新的数据都动态分配一...
  • 代码设置队列长度为5,数组实际大小为6(队列长度加1) 黄色方格是队列头,灰色是未被使用内存,蓝色是队列元素 Example1: 当队列添加满元素时(此时队列元素为5) Example2: 删除Example1中队列3个元素(此时队列元素为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 790
精华内容 316
关键字:

内存队列长度