当前位置:  操作系统/服务器>linux

linux中编写自己的并发队列类(Queue 并发阻塞队列)

    来源: 互联网  发布时间:2014-10-15

    本文导语:  设计并发队列 代码如下:#include #include using namespace std; template class Queue { public:     Queue( )     {         pthread_mutex_init(&_lock, NULL);     }     ~Queue( )     {         pthread_mutex_destroy(&_lock);    }     void push(const T& data)...

设计并发队列

代码如下:

#include
#include
using namespace std;

template
class Queue
{
public:
    Queue( )
    {
        pthread_mutex_init(&_lock, NULL);
    }
    ~Queue( )
    {
        pthread_mutex_destroy(&_lock);
    }
    void push(const T& data);
    T pop( );
private:
    list _list;
    pthread_mutex_t _lock;
};

template
void Queue::push(const T& value )
{
    pthread_mutex_lock(&_lock);
    _list.push_back(value);
    pthread_mutex_unlock(&_lock);
}

template
T Queue::pop( )
{
    if (_list.empty( ))
    {
        throw "element not found";
    }
    pthread_mutex_lock(&_lock);
    T _temp = _list.front( );
    _list.pop_front( );
    pthread_mutex_unlock(&_lock);
    return _temp;
}

上述代码是有效的。但是,请考虑这样的情况:您有一个很长的队列(可能包含超过 100,000 个元素),而且在代码执行期间的某个时候,从队列中读取数据的线程远远多于添加数据的线程。因为添加和取出数据操作使用相同的互斥锁,所以读取数据的速度会影响写数据的线程访问锁。那么,使用两个锁怎么样?一个锁用于读取操作,另一个用于写操作。给出修改后的 Queue 类。

代码如下:

template
class Queue
{
public:
    Queue( )
    {
        pthread_mutex_init(&_rlock, NULL);
        pthread_mutex_init(&_wlock, NULL);
    }
    ~Queue( )
    {
        pthread_mutex_destroy(&_rlock);
        pthread_mutex_destroy(&_wlock);
    }
    void push(const T& data);
    T pop( );
private:
    list _list;
    pthread_mutex_t _rlock, _wlock;
};


template
void Queue::push(const T& value )
{
    pthread_mutex_lock(&_wlock);
    _list.push_back(value);
    pthread_mutex_unlock(&_wlock);
}

template
T Queue::pop( )
{
    if (_list.empty( ))
    {
        throw "element not found";
    }
    pthread_mutex_lock(&_rlock);
    T _temp = _list.front( );
    _list.pop_front( );
    pthread_mutex_unlock(&_rlock);
    return _temp;
}

设计并发阻塞队列

目前,如果读线程试图从没有数据的队列读取数据,仅仅会抛出异常并继续执行。但是,这种做法不总是我们想要的,读线程很可能希望等待(即阻塞自身),直到有数据可用时为止。这种队列称为阻塞的队列。如何让读线程在发现队列是空的之后等待?一种做法是定期轮询队列。但是,因为这种做法不保证队列中有数据可用,它可能会导致浪费大量 CPU 周期。推荐的方法是使用条件变量,即 pthread_cond_t 类型的变量。

代码如下:

template
class BlockingQueue
{
public:
    BlockingQueue ( )
    {
        pthread_mutexattr_init(&_attr);
        // set lock recursive
        pthread_mutexattr_settype(&_attr,PTHREAD_MUTEX_RECURSIVE_NP);
        pthread_mutex_init(&_lock,&_attr);
        pthread_cond_init(&_cond, NULL);
    }
    ~BlockingQueue ( )
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
    }
    void push(const T& data);
    bool push(const T& data, const int seconds); //time-out push
    T pop( );
    T pop(const int seconds); // time-out pop

private:
    list _list;
    pthread_mutex_t _lock;
    pthread_mutexattr_t _attr;
    pthread_cond_t _cond;
};

template
T BlockingQueue::pop( )
{
    pthread_mutex_lock(&_lock);
    while (_list.empty( ))
    {
        pthread_cond_wait(&_cond, &_lock) ;
    }
    T _temp = _list.front( );
    _list.pop_front( );
    pthread_mutex_unlock(&_lock);
    return _temp;
}

template
void BlockingQueue ::push(const T& value )
{
    pthread_mutex_lock(&_lock);
    const bool was_empty = _list.empty( );
    _list.push_back(value);
    pthread_mutex_unlock(&_lock);
    if (was_empty)
        pthread_cond_broadcast(&_cond);
}

并发阻塞队列设计有两个要注意的方面:

1.可以不使用 pthread_cond_broadcast,而是使用 pthread_cond_signal。但是,pthread_cond_signal 会释放至少一个等待条件变量的线程,这个线程不一定是等待时间最长的读线程。尽管使用 pthread_cond_signal 不会损害阻塞队列的功能,但是这可能会导致某些读线程的等待时间过长。

2.可能会出现虚假的线程唤醒。因此,在唤醒读线程之后,要确认列表非空,然后再继续处理。强烈建议使用基于 while 循环的 pop()。

设计有超时限制的并发阻塞队列

在许多系统中,如果无法在特定的时间段内处理新数据,就根本不处理数据了。例如,新闻频道的自动收报机显示来自金融交易所的实时股票行情,它每 n 秒收到一次新数据。如果在 n 秒内无法处理以前的一些数据,就应该丢弃这些数据并显示最新的信息。根据这个概念,我们来看看如何给并发队列的添加和取出操作增加超时限制。这意味着,如果系统无法在指定的时间限制内执行添加和取出操作,就应该根本不执行操作。

代码如下:

template
bool BlockingQueue ::push(const T& data, const int seconds)
{
    struct timespec ts1, ts2;
    const bool was_empty = _list.empty( );
    clock_gettime(CLOCK_REALTIME, &ts1);
    pthread_mutex_lock(&_lock);
    clock_gettime(CLOCK_REALTIME, &ts2);
    if ((ts2.tv_sec – ts1.tv_sec)

    
 
 

您可能感兴趣的文章:

  • linux 消息队列长度的问题
  • linux下消息队列不阻塞
  • LINUX如何调整POSIX消息队列大小
  • Linux消息队列编程问题?
  • linux 两个不同的key生成同样的消息队列ID?
  • Linux下使用C++互斥访问文件+消息队列
  • 大家好,linux内核中等待队列如何使用?哪儿有这些资料?谢谢各位
  • linux下编程显示所有进程,消息队列,急!!!!!!!!!!
  • linux C 语言 多线程读写消息队列
  • linux下 消息队列 超有难度问题
  • 高分求救!linux中两个应用程序之间可以用基于system v的消息队列进行通讯吗?
  • linux消息队列,读而不删怎么弄?
  • linux不同机器间的进程如何共享一个消息队列,并由此互相通信?
  • linux消息队列的问题
  • linux多线程怎么实现等待队列
  • unix/linux平台下进程间通信的问题(消息队列)(紧急求助)
  • linux的IPC消息队列几个简单问题~~~
  • linux如何主动将线程放入到线程调度队列中重新排队?
  • 在LINUX下用C编程有可以直接使用的“队列”数据结构吗?
  • linux中mq_open函数创建的消息队列在哪里
  • Linux下c/c++ boost安装及并发编程库mpi介绍
  • 在linux下,如何进行“互斥”和“并发”的控制?
  • linux下进程并发问题。急!!!求助!!!
  • 基于LINUX 线程的并发通讯服务器
  • linux并发服务器中epoll+多线程分别怎么理解?
  • 如何在linux进行串口操作,并发AT命令?
  • Linux 下libevent如何实现高并发处理的?
  • Linux的并发处理
  • Linux服务器增加并发数
  • linux socket 通信中服务端并发问题,很急!!!
  • 求推荐Linux下利用epoll实现大规模并发服务器架构设计与实现方面的论文or书籍。
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • Linux下read函数默认到底是阻塞的还是非阻塞的?
  • linux 如何用SOCKET设置函数设置阻塞和非阻塞?
  • linux C socke编程 创建的socket默认是阻塞的还是非阻塞的?
  • 请问:我发现在linux上的网络编程时, 若客户端连不上服务端,就会阻塞,但如果是在UNIX上,若连不上,会马上返回,并不阻 塞,怎样让它也能阻塞啊?
  • linux fwrite 阻塞问题
  • linux多线程无法进行阻塞方式的读写操作
  • linux下socket的send函数阻塞问题?
  • Linux里的pthread_create会不会阻塞啊?
  • linux socket fd 写阻塞问题
  • Linux系统刚启动起来的时候为什么会阻塞一下?
  • linux shell如何非阻塞写命名管道
  • linux sem_wait 为什么会阻塞进程?
  • 如何linux 程序中启用其他进程,非阻塞,非popen
  • Linux线程阻塞问题 高手请进
  • linux多线程无法进行阻塞方式的读写操作?
  • linux下如何设置一个socket为非阻塞方式?
  • 在Linux下如何等待线程终止,又不会阻塞
  • linux下的非阻塞读取
  • linux epoll的ET模式和LT模式的主要区别是什么呢?为什么ET模式一定要用非阻塞socket?
  • Linux pthread_cond_timewait 无法阻塞,请大侠快来指点。
  • linux c/c++ IP字符串转换成可比较大小的数字
  • 在win分区上安装linux和独立分区安装linux有什么区别?可以同时安装吗?(两个linux系统)
  • linux哪个版本好?linux操作系统版本详细介绍及选择方案推荐
  • 在虚拟机上安装的linux上,能像真的linux系统一样开发linux程序么?
  • secureCRT下Linux终端汉字乱码解决方法
  • 我重装window后,把linux的引导区覆盖了,进不了linux怎么办?急啊,望热心的人帮助 (现在有linux的盘)
  • Linux c字符串中不可打印字符转换成16进制
  • 安装vmware软件,不用再安装linux系统,就可以模拟linux系统了,然后可以在其上学习一下LINUX下的基本操作 了?
  • Linux常用命令介绍:更改所属用户群组或档案属性
  • 红旗Linux主机可以通过127.0.0.1访问,但如何是连网的Win2000机器通过Linux的IP去访问Linux
  • linux命令大全详细分类介绍及常用linux命令文档手册下载




  • 特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3