多线程下队列的优化

0. 前言

  前段时间在看无锁队列相关的东西时发现了一篇关于加锁队列算法优化的文章,故看了下其原理以及使用C实现了该队列。该队列在Java中类LinkedBlockingQueue以及实现了该功能。

  相关文章:Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms

       多线程队列的算法优化

1. 基本原理

  对于多线程下,多生产者以及多消费者的环境下,可以通过在队首以及队尾分开加锁进行优化。初始时使用一个空节点,在向空队列插入元素或者弹出最后一个元素节点时,可以不需要获取两边的锁(因为需要同时修改tail和head指针,但是加了空节点则可以阻止这种情况的发生)。

2. C简单实现

#include <pthread.h>
#include <stdlib.h>
#include <assert.h>

typedef struct QNode
{
    void *         pValue;
    struct QNode *    pNext;
} QNode;

typedef struct Queue
{
    QNode * pHead;
    QNode * pTail;
    pthread_mutex_t headLock;
    pthread_mutex_t tailLock;
} TQueue;

TQueue * InitTQueue()
{
    TQueue * pQueue = malloc(sizeof(*pQueue));
    assert(pQueue);

    QNode *pEmptyNode = malloc(sizeof(*pEmptyNode));
    assert(pEmptyNode);

    pEmptyNode->pNext = NULL;
    pQueue->pHead = pQueue->pTail = pEmptyNode;
    pthread_mutex_init(&pQueue->headLock, NULL);
    pthread_mutex_init(&pQueue->tailLock, NULL);

    return pQueue;
}

void EnQueue(TQueue *pQueue, void *pValue)
{
    assert(pQueue);

    QNode *pNewNode = malloc(sizeof(*pNewNode));
    pNewNode->pValue = pValue;
    pNewNode->pNext = NULL;

    pthread_mutex_lock(&pQueue->tailLock);

    pQueue->pTail->pNext = pNewNode;
    pQueue->pTail = pNewNode;

    pthread_mutex_unlock(&pQueue->tailLock);
}

void * DeQueue(TQueue *pQueue)
{
    void *pValue = NULL;

    pthread_mutex_lock(&pQueue->headLock);

    QNode *pPopNode = pQueue->pHead;
    if (NULL == pPopNode->pNext)
    {
        pthread_mutex_unlock(&pQueue->headLock);
        return NULL;
    }
    pValue = pPopNode->pNext->pValue;
    pQueue->pHead = pPopNode->pNext;

    pthread_mutex_unlock(&pQueue->headLock);

    free(pPopNode);
    return pValue;
}

void * Producer(void *pArg)
{
    TQueue * pQueue = (TQueue*)pArg;

    const int nMsgNums = 10;

    for (int i = 1; i <= nMsgNums; ++i)
    {
        EnQueue(pQueue, (void*)i);
    }
    EnQueue(pQueue, 0);
}

void * Consumer(void *pArg)
{
    TQueue * pQueue = (TQueue*)pArg;

    while (1)
    {
        int nMsg = (int)DeQueue(pQueue);
        if (nMsg == 0)
        {
            break;
        }
        printf("%u msg[%d]\n", pthread_self(), nMsg);
    }
}

#define MAX_PTHREADS    3

int main(int argc, char const *argv[])
{
    TQueue * pQueue = InitTQueue();

    assert(pQueue);

    pthread_t producerId[MAX_PTHREADS];
    pthread_t consumerId[MAX_PTHREADS];

    for (int i = 0; i < MAX_PTHREADS; ++i)
    {
        pthread_create(&producerId[i], NULL, Producer, (void*)pQueue);
        pthread_create(&consumerId[i], NULL, Consumer, (void*)pQueue);
    }

    for (int i = 0; i < MAX_PTHREADS; ++i)
    {
        pthread_join(producerId[i], NULL);
        pthread_join(consumerId[i], NULL);
    }

    return 0;
}
时间: 2024-12-16 01:33:54

多线程下队列的优化的相关文章

java工程优化——多线程下的单例模式

在最初学习设计模式时,我为绝佳的设计思想激动不已,在以后的工程中,多次融合设计模式,而在当下的设计中,我们已经觉察出了当初设计模式的高瞻远瞩,但是也有一些不足,需要我们去改进,有人说过,世界上没有绝对的事,当然,再简单的事情,环境变了,也会发生变化,今天和大家一起分享在多线程下单例模式的优化. 1,传统 首先,我们回顾下传统的单例(懒汉式)是如何工作的: public class SingletonClass{ private static SingletonClass instance=nul

Window下高性能IOCP模型队列多线程下应用

IOCP,先从概念上认识一下.IOCP全称I/O Completion Port,中文译为I/O完成端口.是Windows平台最高效的I/O模块,现在IIS服务器,就采用IOCP模型.IOCP是一个异步I/O的API,它可以高效地将I/O事件通知给应用程序.与使用select()或是其它异步方法不同的是,现在很多书,文字都直接将IOCP模块和网络编程关联起来,好像IOCP就是和网络打交道的.典型的IOCP模型的使用,是 将一个套接字(socket)与一个完成端口关联了起来,当一个网络事件发生的时

IOS多线程及队列的使用

IOS多线程及队列的使用 分类: ios多线程2013-12-11 17:56 1898人阅读 评论(0) 收藏 举报 多线程 最近搞一款塔防游戏,提到塔防,自然就想到了A星寻路.的确,它是一种高效的寻路算法.但当很多怪物同时在调用A星算法来寻找一条最近的路径来到达目的地时,我发现会很卡.我都不能接受这个卡屏,更何况是玩家呢.所有我一直都在努力去优化A星算法.虽然有所改善,但卡的问题还是存在.实在没辙了,我想到了队列线程.之前都没接触过这个东东,还好在网上找到很详细的线程介绍.当然,我只是用到了

转发 FMDB多线程下&quot;is currently in use&quot; 或者 &quot;database is locked&quot; 问题

FMDB多线程下"is currently in use" 或者 "database is locked" 问题 问题一: "is currently in use" 出现的场景是这样的,多线程操作数据库,每个线程都使用了FMDatabase实例(注意没有使用FMDatabaseQueue). 问题二:“database is locked"出现的场景是这样的,多线程操作数据库,每个线程各自创建了FMDatabaseQueue实例操作数

普通int值在多线程下的递增操作

Java针对多线程下的数值安全计数器设计了一些类,这些类叫做原子类,其中一部分如下:  java.util.concurrent.atomic.AtomicBoolean;  java.util.concurrent.atomic.AtomicInteger;  java.util.concurrent.atomic.AtomicLong;  java.util.concurrent.atomic.AtomicReference;  下面是一个对比 AtomicInteger 与 普通 int

【iOS开发】多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用

http://blog.csdn.net/crycheng/article/details/21799611 本篇文章主要介绍下多线程下NSOperation.NSBlockOperation.NSInvocationOperation.NSOperationQueue的使用,列举几个简单的例子. 默认情况下,NSOperation并不具备封装操作的能力,必须使用它的子类,使用NSOperation子类的方式有3种: 1> 自定义子类继承NSOperation,实现内部相应的方法 2> NSB

Java多线程 阻塞队列和并发集合

转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的线程安全的集合类,通过下面的学习,您需要掌握这些集合的特点是什么,底层实现如何.在何时使用等问题. 3.1 BlockingQueue接口 java阻塞队列应用于生产者消费者模式.消息传递.并行任务执行和相关并发设计的大多数常见使用上下文. BlockingQueue在Queue接口基础上提供了额外

多线程下的资源同步访问

在一个应用程序中使用多线程 好处是每一个线程异步地执行. 对于Winform程序,可以在后台执行耗时操作的同时,保持前台UI正常地响应用户操作. 对于Service.对于客户端的每一个请求,可以使用一个单独的线程来进行处理.而不是等到前一个用户的请求被完全处理完毕后,才能接着处理下一个用户的请求. 同时,异步带来的问题是,必须协调对资源(文件,网络,磁盘)的访问. 否则,会造成在同一时间两个以上的线程访问同一资源,并且这些线程间相互未知,导致不可预测的数据问题. Lock/Monitor:防止线

多线程下的进程同步(线程同步问题总结篇)

之前写过两篇关于线程同步问题的文章(一,二),这篇中将对相关话题进行总结,本文中也对.NET 4.0中新增的一些同步机制进行了介绍. 首先需要说明的是为什么需要线程功能同步.MSDN中有这样一段话很好的解释了这个问题: 当多个线程可以调用单个对象的属性和方法时,对这些调用进行同步处理是非常重要的.否则,一个线程可能会中断另一个线程正在执行的任务,使该对象处于一种无效状态. 也就说在默认无同步的情况下,任何线程都可以随时访问任何方法或字段,但一次只能有一个线程访问这些对象.另外,MSDN中也给出定