POSIX多线程【一】:简单队列simple queue的基础上使用内部互斥锁和条件变量来控制并发以达到线程安全的目的,其主要用于 [生产者-消费者] 队列.

1.BlockingQueue初始化时会确定队列容量(_capacity),如果队列已满(capacity=0),则会阻塞enqueue操作.

2.关闭BlockingQueue(调用queue_free)是一个延迟的操作,它会等待所有元素都dequeue,期间,该队列的一切enqueue操作将无效.

3.此代码未经生产环境检验,仅供学习参考.

BlockingQueue.h

#ifndef CUR_BLOCKINGQUEUE_H
#define CUR_BLOCKINGQUEUE_H
#include <stdlib.h>
#include <pthread.h> struct node{
int value;
struct node * next;
}; typedef struct BlockingQueue_ST{
int capacity,remaining,closed;
struct node * head, *tail;
pthread_mutex_t queue_mutex;
pthread_cond_t cond_not_full;
pthread_cond_t cond_not_empty;
pthread_cond_t cond_empty;
}BlockingQueue; extern BlockingQueue* empty_queue(int _capacity);
extern int queue_free(BlockingQueue *q);
extern int is_empty(const BlockingQueue *q);
extern int is_full(const BlockingQueue *q);
extern int enqueue(struct node *item, BlockingQueue *q);
extern struct node* dequeue(BlockingQueue *q); #endif

BlockingQueue.c

#include "BlockingQueue.h"
#include <stdio.h> BlockingQueue* empty_queue(int _capacity)
{
BlockingQueue *q = malloc(sizeof(BlockingQueue));
q->head = q->tail = NULL;
q->capacity = q->remaining = _capacity;
q->closed = ;
pthread_mutex_init(&q->queue_mutex , NULL);
pthread_cond_init(&q->cond_not_full , NULL);
pthread_cond_init(&q->cond_not_empty , NULL);
pthread_cond_init(&q->cond_empty , NULL);
return q;
} int queue_free(BlockingQueue *q)
{
pthread_mutex_lock(&q->queue_mutex);
printf("close queue...\n");
q->closed = ;
//等待cond_empty
while(!is_empty(q))
{
pthread_cond_wait(&q->cond_empty, &q->queue_mutex);
}
free(q);
pthread_mutex_unlock(&q->queue_mutex);
printf("closed...\n");
} int is_empty(const BlockingQueue *q)
{
return q->capacity == q->remaining;
} int is_full(const BlockingQueue *q)
{
return q->remaining == ;
} int enqueue(struct node *item, BlockingQueue *q)
{ if(q->closed) goto err;
//lock
pthread_mutex_lock(&q->queue_mutex);
//等待cond_not_full
while(is_full(q))
{
pthread_cond_wait(&q->cond_not_full, &q->queue_mutex);
} if(is_empty(q))
{
q->head = q->tail = item;
//通知所有等待cond_not_empty的线程
pthread_cond_broadcast(&q->cond_not_empty);
}
else
{
q->tail->next = item;
q->tail = item;
}
q->remaining--;
//unlock
pthread_mutex_unlock(&q->queue_mutex); return ;
err :
return -;
} struct node* dequeue(BlockingQueue *q)
{ //已经关闭的空队列
if(q->closed && is_empty(q)) goto err;
//lock
pthread_mutex_lock(&q->queue_mutex);
//空队列,等待cond_not_empty
while(!q->closed && is_empty(q))
{
pthread_cond_wait(&q->cond_not_empty, &q->queue_mutex);
}
//take
struct node * temp = q->head;
q->head = q->head->next; //在未关闭队列的情况下,唤醒enqueue等待线程
if(!q->closed && is_full(q))
{
pthread_cond_broadcast(&q->cond_not_full); //TODO 1
}
q->remaining++;
//唤醒关闭队列线程
if(q->closed && is_empty(q))
{
pthread_cond_signal(&q->cond_empty);//TODO 2
} //注意:TODO 1和TODO 2其实是互斥的,不可能同时满足条件
//必须先判断是否激活cond_not_full然后remaining++
//最后再判断是否激活cond_empty
//unlock
pthread_mutex_unlock(&q->queue_mutex);
return temp;
err:
return NULL;
}

测试代码 : main.c

#include<stdio.h>
#include<stdlib.h>
#include "BlockingQueue.h"
extern void* func_put(void* _q); BlockingQueue *q;
pthread_t thread1,thread2;
void main()
{
q = empty_queue();
pthread_create(&thread1,NULL,func_put,(void*)q);
pthread_create(&thread2,NULL,func_put,(void*)q); int i;
for(i=; i<=; i++)
{
struct node * item = (struct node *)malloc(sizeof(struct node));
item->value = i;
item->next = NULL;
enqueue(item,q);
printf("enqueue -> thread : %d, value : %d, remaining : %d\n",pthread_self(),i,q->remaining);
sleep();
}
queue_free(q);
} void* func_put(void* _q)
{
BlockingQueue *q = (BlockingQueue*)_q;
struct node *item;
while((item = dequeue(q)) != NULL)
{
printf("dequeue -> thread : %d, value : %d, remaining : %d\n",pthread_self(), item->value,q->remaining);
free(item);
sleep();
}
}

测试结果 :

数据结构【二】:简单阻塞队列BlockingQueue的更多相关文章

  1. spring线程池ThreadPoolTaskExecutor与阻塞队列BlockingQueue

    一: ThreadPoolTaskExecutor是一个spring的线程池技术,查看代码可以看到这样一个字段: private ThreadPoolExecutor threadPoolExecut ...

  2. Java并发指南11:解读 Java 阻塞队列 BlockingQueue

    解读 Java 并发队列 BlockingQueue 转自:https://javadoop.com/post/java-concurrent-queue 最近得空,想写篇文章好好说说 java 线程 ...

  3. java并发包——阻塞队列BlockingQueue及源码分析

    一.摘要 BlockingQueue通常用于一个线程在生产对象,而另外一个线程在消费这些对象的场景,例如在线程池中,当运行的线程数目大于核心的线程数目时候,经常就会把新来的线程对象放到Blocking ...

  4. Java并发(十八):阻塞队列BlockingQueue

    阻塞队列(BlockingQueue)是一个支持两个附加操作的队列. 这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空.当队列满时,存储元素的线程会等待队列可用. 阻塞队列常用于生产 ...

  5. Java并发编程-阻塞队列(BlockingQueue)的实现原理

    背景:总结JUC下面的阻塞队列的实现,很方便写生产者消费者模式. 常用操作方法 常用的实现类 ArrayBlockingQueue DelayQueue LinkedBlockingQueue Pri ...

  6. 并发编程-concurrent指南-阻塞队列BlockingQueue

    阻塞队列BlockingQueue,java.util.concurrent下的BlockingQueue接口表示一个线程放入和提取实例的队列. 适用场景: BlockingQueue通常用于一个线程 ...

  7. JUC---01阻塞队列(BlockingQueue)

    一.什么是阻塞队列 阻塞队列是一个队列,在数据结构中起的作用如上图:当队列是空的,从队列中获取元素的操作将会被阻塞:当队列是满的,从队列中添加元素的操作将会被阻塞 1.为什么需要BlockingQue ...

  8. Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例

    Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...

  9. 阻塞队列BlockingQueue之ASynchronousQueue

    一.SynchronousQueue简介 Java 6的并发编程包中的SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除 ...

随机推荐

  1. WebBrowser的各种使用方法(未完待续)(XE8+WIN7)

    相关资料: 占时想不起来了,有时间我补上吧. 程序下载: http://download.csdn.net/detail/zhujianqiangqq/9666390 实例代码: unit Unit1 ...

  2. 成功获取并更改中兴F660光猫的超级用户密码解除四台限制

    上次雷雨后更换的中兴的F660光猫还是很不错的,很稳定,不过超级密码确实记不住,找了些资料,今天成功的更改了密码,简要的写出过程以备下次参考: 第一步:获取超级密码(已知用户名telecomadmin ...

  3. [iOS微博项目 - 3.0] - 手动刷新微博

    github: https://github.com/hellovoidworld/HVWWeibo   A.下拉刷新微博 1.需求 在“首页”界面,下拉到一定距离的时候刷新微博数据 刷新数据的时候使 ...

  4. 要后台控制前台的的CSS样式,我们可以加入ASP.NET Literal 控件

    ASP.NET Literal 控件,用于在页面上显示文本.此文本是可编程的. 我用它来制作了 ) { this.LtdMemberPromotion7.Text = "<style ...

  5. oracle 的行级触发器

    create or replace trigger tri_insertAcceptList after insert on STDOC.DEVELOPER for each row DECLARE ...

  6. CodeForces 710C Magic Odd Square (n阶奇幻方)

    题意:给它定一个n,让你输出一个n*n的矩阵,使得整个矩阵,每行,每列,对角线和都是奇数. 析:这个题可以用n阶奇幻方来解决,当然也可以不用,如果不懂,请看:http://www.cnblogs.co ...

  7. SpringMVC3.2+JPA使用注解的方式环境搭建

    ==============================entity=========================================================package ...

  8. Fragment进阶

    fragment之间的通信,fragment和Activity生命周期之间的关系 通过上一篇浅显的学习了一下,怎么在Activity中添加fragment.在介绍fragment之间的通信之前,我们来 ...

  9. 如何判断js中的数据类型(转)

    如何判断js中的数据类型:typeof.instanceof. constructor. prototype方法比较 如何判断js中的类型呢,先举几个例子: var a = "iamstri ...

  10. eclipse提示servlet不存在 的解决办法

    在以前的版本中,Tomcat的common/lib目录下有一个名为servlet-api.jar的包,把它拷贝至你的java安装目录下jre/lib/ext下就可以了. 如果是:tomcat6就在To ...