TCP服务器实现-start函数启动过程-线程池消息队列实现(基于数组)

版权声明:转载请注明来源 https://blog.csdn.net/u013702678/article/details/81212964

这里我们接着第三篇的分析,分析另外一种线程池消息队列的实现和其他变量的初始化,这里是通过环装的数组实现队列,这里通过SW_USE_RINGQUEUE_TS区分定义了两种不同队列的实现,两种我们都简单分析一下。

首先分析基于cas控制队列操作的环状队列。

//基于数组实现的消息队列,swRingQueue是队列的抽象,buffer_size表示队列大小
int swRingQueue_init(swRingQueue *queue, int buffer_size)
{
    queue->size = buffer_size;//设置队列大小
    queue->flags = (char *)sw_malloc(queue->size);//从堆申请空间,这里吐槽一点flags这个变量名取的太有歧义了,这里表示的意思是操作数据时的序号。
    if (queue->flags == NULL)//申请空间失败
    {
        return -1;
    }
    //队列的数据空间,数据为类型为void*,用数组表示,所以最终类型为void**
    queue->data = (void **)sw_calloc(queue->size, sizeof(void*));
    if (queue->data == NULL)//申请空间失败
    {
        sw_free(queue->flags);//flags表示队列的部分属性,数据空间失败时,这部分也没什么意思,也需要释放,不然有内存泄露的风险。
        return -1;
    }

    queue->head = 0;//队列头部序号
    queue->tail = 0;//队列尾部序号
    memset(queue->flags, 0, queue->size);//空间初始化
    memset(queue->data, 0, queue->size * sizeof(void*));//数据空间初始化
    return 0;
}

//队列里面push元素
int swRingQueue_push(swRingQueue *queue, void * ele)
{
    //队列个数有效性判断,即队列元素个数不能大于等于队列size。
    if (!(queue->num < queue->size))
    {
        return -1;
    }

    int cur_tail_index = queue->tail;//队列尾部序号
    char * cur_tail_flag_index = queue->flags + cur_tail_index;//队列序号空间加上尾部序号,则表示队列尾部的序号空间。
    //cas操作判断,目前是否可以push元素,就cas的old为0,new值为1
    while (!sw_atomic_cmp_set(cur_tail_flag_index, 0, 1))
    {
        cur_tail_index = queue->tail;//队列尾部序号
        cur_tail_flag_index = queue->flags + cur_tail_index;//队列序号空间加上尾部序号,则表示队列尾部的序号空间。
    }
    
    //更新最新的队列尾部空间,这里是环状的,所以需要做mod操作
    int update_tail_index = (cur_tail_index + 1) % queue->size;
    //cas操作,更新队列尾部序号
    sw_atomic_cmp_set(&queue->tail, cur_tail_index, update_tail_index);

    *(queue->data + cur_tail_index) = ele;//存储元素

    sw_atomic_fetch_add(cur_tail_flag_index, 1);//cas更新尾部序号,即序号+1操作
    sw_atomic_fetch_add(&queue->num, 1);//cas更新队列元素个数,即队列个数+1
    return 0;
}

下面分析普通的,也就是非多线程更新的环状队列。

//队列初始化,swRingQueue指向队列,buffer_size表示队列空间大小
int swRingQueue_init(swRingQueue *queue, int buffer_size)
{
    //队列数据空间申请和初始化
    queue->data = sw_calloc(buffer_size, sizeof(void*));
    if (queue->data == NULL)//申请空间失败
    {
        swWarn("malloc failed.");
        return -1;
    }

    queue->size = buffer_size;//设置队列的个数
    queue->head = 0;//队列头部序号初始化
    queue->tail = 0;//队列尾部序号初始化
    queue->tag = 0;//为空为满的标志位
    return 0;
}

//入队操作,queue为指向队列的指针,push_data为要入队的数据
int swRingQueue_push(swRingQueue *queue, void *push_data)
{
    //队列已满,则抛错
    if (swRingQueue_full(queue))
    {
        return SW_ERR;
    }

    queue->data[queue->tail] = push_data;//队尾添加元素
    queue->tail = (queue->tail + 1) % queue->size;//更新队尾序号
    
    //队头和队尾相等,则标记队列满
    if (queue->tail == queue->head)
    {
        queue->tag = 1;
    }

    return SW_OK;
}

猜你喜欢

转载自blog.csdn.net/u013702678/article/details/81212964