条件锁和队列的使用

本文深入讲解了队列的基本操作,包括创建、取队列、放回队列等,并详细介绍了如何在代码中实现这些操作,特别关注了等待时间和生产消费模型的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 描述

  队列的基本操作包括队列的创建、取队列、放回队列,但是取队列还需加上等待时间、还有放入等待时间。队列的操作是一个典型的生产消费模型,相关的说明可以参考博客:(https://blog.csdn.net/Pro__rookie/article/details/87358814)。
  # 2 代码主要实现
	typedef struct statck_create_tag
	{
		int len;
		char name[128];
	}statck_create_t;
	
	typedef struct statck_create_obj_tag
	{
		int len;
		int cur_wr_site;
		int cur_re_site;
		int count;
		char name[128];
		void **statck_que;
		pthread_mutex_t lock;
		pthread_cond_t condPush;
		pthread_cond_t condPop;			
	}statck_create_obj_t;

	int Statck_Create(void **hd,statck_create_t param)
	{
		int ret = 0;
		statck_create_obj_t *pobj = NULL;
		pobj = (statck_create_obj_t *)malloc(sizeof(statck_create_obj_t ));
		if(!pobj)
			return -1;
		memset(pobj,0,sizeof(statck_create_obj_t ));
		pobj->len = param.len;
		assert(strlen(param.name) <= 128);
		snprintf(pobj->name,strlen(param.name)-1,"%s",param.name);
		
		pobj->statck_que = (void**)malloc(pobj->len*sizeof(void*));
		if(!pobj->statck_que)
			return -1;
		memset((void*)pobj->statck_que,0,pobj->len*sizeof(void*));

		ret = pthread_mutex_init(&pobj->lock,NULL);
		assert(0 == ret);

		ret = pthread_cond_init(&pobj->condPush,NULL);
		assert(0 == ret);

		ret = pthread_cond_init(&pobj->condPop,NULL);
		assert(0 == ret);
	
		*hd = pobj;
		return 0;
	}

	int Statck_push(void *hd,void *value,int time_out)
	{
		int ret = -1;
		struct timeval tv;
		struct timespec waitTime;
		statck_create_obj_t *pobj = (statck_create_obj_t *)hd;
		assert(NULL != pobj);

		pthread_mutex_lock(&pobj->lock);
		while(1)
		{
			if(pobj->count < pobj->len)
			{
				pobj->statck_que[pobj->cur_wr_site] = value;
				//pobj->cur_wr_site记录当前的位置,依次0 1 2 .... pobj->len-1 0 1 ....
				pobj->cur_wr_site = (pobj->cur_wr_site+1)%pobj->len;
				pobj->count++;
				//生产者,给pop发信号,已经存了数据,可以来取数据了
				pthread_cond_signal(&pobj->condPop);
				ret = 0;
				break;
			}else
			{
				if(TIME_OUT_NONE == time_out)
				{
					printf("push %s value %p fail\n",pobj->name,value);
					ret = -1;
					break;
				}else
				{
					if(TIME_OUT_FOREVER == time_out)
					{
						ret = pthread_cond_wait(&pobj->condPush,&pobj->lock);
						if(0 != ret)
						{
							printf("pthread_cond_wait failed,ret:%d\n",ret);
							break;
						}
					}else
					{
						memset(&tv,0,sizeof(sruct timeval));
						ret = gettimeofday(&tv,NULL);
						if(0 == ret)
						{
							memset(&waitTime,0,sizeof(struct timespec));
							waitTime.tv_sec = (long)time_out/1000;
							waitTime.tv_nsec = ((long)time_out%1000)*1000000;
							waitTime.tv_sec += tv.tv_sec;
							waitTime.tv_nsec += tv.tv_usec*1000;
							if(waitTime.tv_nsec >= 1000000000)
							{
								waitTime.tv_sec += 1;
								waitTime.tv_nsec %= 1000000000;
							}
							/*tv_nsec 此值有范围限制的,就是不能超过1秒即1000000000纳秒。如果超出1秒,就要在tv_sec 此值增加一秒;tv_nsec 减去一秒。如果tv_nsec 此值溢出,调用pthread_cond_timedwait函数,会立马返回。*/
							//pthread_cond_timedwait中的waitTime需要绝对时间,所以要先取到当前时间
							ret = pthread_cond_timedwait(&pobj->condPush,&pobj->lock,&waitTime);
							if(ETIMEDOUT == ret)
							{
								ret = ETIMEDOUT;
								break;
							}else
							{
								printf("pthread_cond_timedwait failed %d\n",ret);
								break;
							}
						}
					}
				}
			}
		}
		pthread_mutex_unlock(&pobj->lock);
		return ret;
	}

int Statck_pop(void *hd,void **value,int time_out)
{
	int ret = -1;
	struct timeval tv;
	struct timespec waitTime;
	statck_create_obj_t *pobj = (statck_create_obj_t *)hd;
	assert(NULL != pobj);

	pthread_mutex_lock(&pobj->lock);
	while(1)
	{
		if(pobj->count > 0)
		{
			*value = (void*)pobj->statck_que[pobj->cur_re_site];
			pobj->cur_re_site = (pobj->cur_re_site+1)%pobj->len;
			pobj->count--;
			pthread_cond_signal(&pobj->condPush);
			ret = 0;
			break;
		}else
		{
			if(TIME_OUT_FOREVER == time_out)
			{
				ret = pthread_cond_wait(&pobj->condPop,&pobj->lock);
				if(0 != ret)
				{
					printf("pthread_cond_wait failed,ret:%d\n",ret);
					break;
				}
		     }else
			{
				memset(&tv,0,sizeof(sruct timeval));
				ret = gettimeofday(&tv,NULL);
				if(0 == ret)
				{
					memset(&waitTime,0,sizeof(struct timespec));
					waitTime.tv_sec = (long)time_out/1000;
					waitTime.tv_nsec = ((long)time_out%1000)*1000000;
					waitTime.tv_sec += tv.tv_sec;
					waitTime.tv_nsec += tv.tv_usec*1000;
					if(waitTime.tv_nsec >= 1000000000)
					{
						waitTime.tv_sec += 1;
						waitTime.tv_nsec %= 1000000000;
					}
					ret = pthread_cond_timedwait(&pobj->condPop,&pobj->lock,&waitTime);
					if(ETIMEDOUT == ret)
					{
						ret = ETIMEDOUT;
						break;
					}else
					{
						printf("pthread_cond_timedwait failed %d\n",ret);
						break;
					}
				}
			}			
		}
	}
		pthread_mutex_unlock(&pobj->lock);
		return ret;
}

int main(int argv,char **argc)
{
	int ret = 0 , i = 0  , que_size = 10;
	void *hd = NULL;
	statck_create_t param;
	
	param.len = que_size;
	snprintf(param.name,128,"que_test");
	ret = Statck_Create(&hd,param);
	assert(0 == ret);
	
	for(i = 0 ; i < que_size ; i++)
	{
		int *value = (int*)malloc(sizeof(int));
		*value = i;
		ret = Statck_push(hd,value,TIME_OUT_NONE);
	}
	for(i = 0 ; i < que_size ; i++)
	{
		int *pop_value = NULL;
		ret = Statck_pop(hd,(void**)pop_value,TIME_OUT_NONE);
		if(pop_value)
			printf("pop_value = %d\n",*pop_value);
	}
	return 0;
}
CLH队列条件队列是两个不同的概念。 CLH队列是AQS(AbstractQueuedSynchronizer)内部维护的一种FIFO队列,用于实现同步机制。它采用双向链表保存,使用prevnext相互链接,每个节点表示一个线程,按照线程的先后顺序排队等待获取资源。CLH队列的特点是线程之间通过不断自旋来检查前一个线程是否已经释放资源,从而实现高效的等待队列条件队列则是AQS中的一种数据结构,用于实现线程的等待与唤醒机制。条件队列使用单向列表保存的,使用nextWaiter来连接节点。每个节点表示一个等待条件的线程,当线程调用await()方法时,它将被移动到条件队列中等待。当满足某个条件时,其他线程可以调用signal()或signalAll()方法来唤醒条件队列中的线程。 总结起来,CLH队列用于实现同步机制中的线程排队等待获取资源,而条件队列用于实现线程的等待与唤醒机制。它们分别采用不同的数据结构链接方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [并发之AQS原理(二) CLH队列与Node解析](https://blog.csdn.net/weixin_30561177/article/details/99097474)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [浅谈Java并发 J.U.C之AQS:CLH同步队列](https://download.csdn.net/download/weixin_38694336/12749163)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值