Linux 多线程通信.全局变量,结构体,队列,项目模版(一)

这是一个使用C语言实现的帧队列管理程序,包括打开、关闭、发送、接收、中止和清空队列的函数。通过互斥锁实现线程安全的帧数据通信,适用于多线程环境中的数据交换。

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

一、使用全局变量,结构体,队列进行通信,

多线程共用地址空间,全局变量,定义一个大容器结构体,装所有数据,自定义一个队列,数据类型是结构体类型。

1、Frame_Queue.h

#ifndef QUEUE_Frame_H_
#define QUEUE_Frame_H_

#define MAX_PKT_NUM 1500

#pragma pack(1)
typedef struct Frame_Pkt
{
	SX_U16	u16SyncHead;		
	SX_U8		u8Cmd;
	SX_U8	data[1500];
} T_Frame_Pkt, *PT_Frame_Pkt;
#pragma pack()

typedef struct QUEUE_Frame{
	PT_Frame_Pkt 	PtFrame;	
	SX_S32			s32QueueDepth;
	SX_S32  		s32IndexR;
	SX_S32  		s32IndexW;
	SX_S32  		s32Count;
	SX_BOOL			bAbortRequest;
	pthread_mutex_t	mutex;
	pthread_cond_t 	cond;
}T_QUEUE_Frame, *PT_QUEUE_Frame;

extern	PT_QUEUE_Frame 	QUEUE_Frame_Creat( SX_S32 depth );
extern	void 			QUEUE_Frame_Destroy( PT_QUEUE_Frame handle );
extern	SX_S32 			QUEUE_Frame_Write(PT_QUEUE_Frame handle, PT_Frame_Pkt Frame, SX_BOOL block);
extern	SX_S32 			QUEUE_Frame_Read( PT_QUEUE_Frame handle, PT_Frame_Pkt Frame, SX_BOOL block);
extern	void 			QUEUE_Frame_Abort( PT_QUEUE_Frame handle );
extern	void 			QUEUE_Frame_Flush( PT_QUEUE_Frame handle );

#endif 

2、Frame_Queue.c
//创建一个队列

#include"Frame_Queue.h"

PT_QUEUE_Frame QUEUE_Frame_Creat(SX_S32 size)
{
	PT_QUEUE_Frame handle = (PT_QUEUE_Frame)xine_xmalloc(sizeof(T_QUEUE_Frame));
	if( handle == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		return NULL;
	}
	
	if (pthread_mutex_init( &handle->mutex, NULL ) != 0)
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		QUEUE_Frame_Close( handle );
		return NULL;
	}
	
	if( pthread_cond_init(&handle->cond, NULL) != 0 )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		QUEUE_Frame_Close( handle );
		return NULL;
	}
	
	handle->PtFrame = (PT_Frame_Pkt)xine_xmalloc(sizeof(T_Frame_Pkt) * size);
	if( handle->PtFrame == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		QUEUE_Frame_Close( handle );
		return NULL;
	}
	
	handle->s32QueueDepth = size;
	handle->s32IndexR = 0;
	handle->s32IndexW = 0;
	handle->s32Count = 0;
	handle->bAbortRequest = SX_FALSE;
	
	return handle;
}

//销毁队列

void QUEUE_Frame_Destroy( PT_QUEUE_Frame handle )
{
	if( handle )
	{
		if( handle->PtFrame )
		{
			xine_freep(  (void *)&(handle->PtFrame) );
		}
		
		pthread_mutex_destroy( &handle->mutex );
		pthread_cond_destroy(&handle->cond);
		
		xine_freep(  (void *)&handle);
	}
	return;
}

//使用互斥锁结合条件变量,实现同步,自定义一个队列,写队列

SX_S32 QUEUE_Frame__Write( PT_QUEUE_Frame handle, PT_Frame_Pkt Frame,, SX_BOOL block)
{
	if( handle == NULL || Frame == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		return -1;
	}
	pthread_mutex_lock( &(handle->mutex) );
	
	if( (handle->s32IndexW + 1) % handle->s32QueueDepth == handle->s32IndexR )//队列被写满了,如果要换成循环队列,看我别的文章
	{
		pthread_mutex_unlock( &(handle->mutex) );
		//TRACE(DL_WARNING, "queue full\n");		//tx bus_send_cmd fifo is always full in working phase
		return 0;
	}
	
	PT_Frame_Pkt PtFrame = handle->PtFrame + handle->s32IndexW;	//获取队列的首地址,写偏移量,进行偏移,下一个要的位移地址
	#if	1
	*PtFrame = *Frame;//第一种方法是通过指针,速度很快
	#else
	memcpy( ptCmd->szSync, cmd->szSync, sizeof(ptCmd->szSync) );//第二种方法是通过memcopy的方式,将数据写入队列

	ptCmd->s8ChNo		= cmd->s8ChNo;
	ptCmd->s8CmdIndex	= cmd->s8CmdIndex;
	ptCmd->s16CmdPeriod	= cmd->s16CmdPeriod;
	ptCmd->s8LibIndex	= cmd->s8LibIndex;
	ptCmd->u8CmdLength	= cmd->u8CmdLength;
	ptCmd->s8CmdFormat	= cmd->s8CmdFormat;
	memcpy( ptCmd->szReserved1, cmd->szReserved1, sizeof(cmd->szReserved1) );
	memcpy( ptCmd->szCmd, cmd->szCmd, MIN(ptCmd->u8CmdLength, sizeof(ptCmd->szCmd)) );
	
	ptCmd->s32StatusLength = cmd->s32StatusLength;
	memcpy( ptCmd->szStatus, cmd->szStatus, MIN(ptCmd->s32StatusLength, sizeof(ptCmd->szStatus)) );
	ptCmd->s32LastTime	= cmd->s32LastTime;
	ptCmd->s32Sn		= cmd->s32Sn;
	ptCmd->ptBk			= cmd->ptBk;
	ptCmd->ptCh			= cmd->ptCh;
	ptCmd->ptCmd_Myself = cmd->ptCmd_Myself;
	ptCmd->next			= cmd->next;
	#endif
	
	handle->s32IndexW = (handle->s32IndexW+1) % handle->s32QueueDepth;//队列写偏移指针,位移加1
	handle->s32Count++;//通过这个值,很容易判断,队列是否写满s32Count ?= size
	
	if ( !block)	// 阻塞标记,1(阻塞模式),0(非阻塞模式)
	{
	}
	else
	{
		pthread_cond_signal( &handle->cond );
	}
	
	pthread_mutex_unlock( &handle->mutex );
	return 1;
}

//使用互斥锁结合条件变量,实现同步,自定义一个队列,读队列

SX_S32 QUEUE_FrameRead(PT_QUEUE_Frame handle, PT_Frame_Pkt Frame, SX_BOOL block)
{
	if( handle == NULL || Frame == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		return -1;
	}
	SX_S32  	ret = 1;
	pthread_mutex_lock( &(handle->mutex) );

	for (;;)
	{
		if (handle->bAbortRequest) // 异常
		{
			ret = -1;							
			break;
		}

		if( handle->s32IndexW == handle->s32IndexR)			//empty		//if( _s32Count == 0 )
		{
			if ( !block)						// 阻塞标记,1(阻塞模式),0(非阻塞模式)
			{
				ret = 0; 						// 非阻塞模式,没东西直接返回0
				break;
			}
			else
			{
				pthread_cond_wait(&handle->cond, &handle->mutex);
			}
		}
		else//队列有数据
		{
			PT_Frame_Pkt PtFrame = handle->PtFrame + handle->s32IndexR;//获取队列的首地址,读偏移量,进行偏移,下一个要的位移地址
			
			#if 1//第一种方法是通过指针,速度很快
			*Frame = *PtFrame;
			#else//第二种方法是通过memcopy的方式,将数据写入队列
			
			memcpy( cmd->szSync, ptCmd->szSync, sizeof(cmd->szSync) );
			cmd->s8ChNo			= ptCmd->s8ChNo;
			cmd->s8CmdIndex		= ptCmd->s8CmdIndex;
			cmd->s16CmdPeriod	= ptCmd->s16CmdPeriod;
			cmd->s8LibIndex		= ptCmd->s8LibIndex;
			cmd->u8CmdLength	= ptCmd->u8CmdLength;
			cmd->s8CmdFormat	= ptCmd->s8CmdFormat;
			memcpy( cmd->szReserved1, ptCmd->szReserved1, sizeof(ptCmd->szReserved1) );
			memcpy( cmd->szCmd, ptCmd->szCmd, MIN(cmd->u8CmdLength, sizeof(cmd->szCmd)) );
			
			cmd->s32StatusLength = ptCmd->s32StatusLength;
			memcpy( cmd->szStatus, ptCmd->szStatus, MIN(cmd->s32StatusLength, sizeof(cmd->szStatus)) );
			cmd->s32LastTime	= ptCmd->s32LastTime;
			cmd->s32Sn		= ptCmd->s32Sn;
			cmd->ptBk			= ptCmd->ptBk;
			cmd->ptCh			= ptCmd->ptCh;
			cmd->ptCmd_Myself 	= ptCmd->ptCmd_Myself;
			cmd->next		= ptCmd->next;
			#endif		
			
			//队列指针往后移走	
			handle->s32IndexR = (handle->s32IndexR + 1) % handle->s32QueueDepth;//队列读偏移指针,位移加1
			if( handle->s32Count > 0 )
			{
				handle->s32Count--;
			}
			ret = 1;
			break;
		}
	}
	
	pthread_mutex_unlock( &(handle->mutex)  );
	return ret;
}

异常终止,退出

void QUEUE_Frame_Abort(PT_QUEUE_Frame handle) 
{
	if( handle == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		return;
	}
	
	pthread_mutex_lock( &(handle->mutex) );
	handle->bAbortRequest = SX_TRUE;
	pthread_cond_signal(&handle->cond);
	pthread_mutex_unlock( &handle->mutex);
	
	return;
}

清除,重置

void QUEUE_Frame_Flush(PT_QUEUE_Frame handle)
{
	if( handle == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		return;
	}
	
	pthread_mutex_lock( &(handle->mutex) );

	handle->s32IndexR	= 0;
	handle->s32IndexW	= 0;
	handle->s32Count	= 0;
	
	handle->bAbortRequest = 0;
	
	pthread_mutex_unlock( &(handle->mutex)  );
	return;
}

3、main.c,调用模版,例子

1、线程A,通过网络接收大量的数据,并写入队列


PT_QUEUE_Frame	ptFrameQueue;
T_Frame_Pkt		FrameRcvQueue;
T_Frame_Pkt		FrameSendQueue;
//static SX_U32 cnt  = 0;
SX_S32  QUEUE_Frame_WriteData(PT_Receiver handle, void *buf, SX_S32 timeoutMs )
{
	if( handle == NULL )
	{
		TRACE(DL_ERROR, "DL_ERROR\n");
		return 0;
	}
	SX_U8 *pDst = NULL;
	SX_S32 ret, sret, retval;
	SX_S64 max_fd;
	fd_set readfds;
	struct timeval tv;
	int i  = 0;
	FD_ZERO(&readfds);	
	FD_SET( handle->sockfd, &readfds );

	max_fd = handle->sockfd;	
	tv.tv_sec  = timeoutMs/1000;	
	tv.tv_usec = (timeoutMs%1000)*1000;	
	
	retval = select( max_fd + 1, &readfds, NULL, NULL, &tv );
	if ( retval > 0 )
	{
		
		sret = recvfrom( handle->sockfd, (SX_S8 *)buf, UDP_MAX_LEN, 0, (struct sockaddr *)&(handle->cliaddr), 
		&(handle->cliaddr_len) );
	
		if ( sret > 0 )
		{
			SX_U8 * pDst = (SX_U8 *)malloc(UDP_MAX_LEN);
			pDst = (SX_U8 *)&handle->FrameSendQueue.data;
			memcpy( (SX_S8 *)pDst, (SX_S8 *)buf,sret);

			if(handle->ptFrameQueue == NULL || &(handle->FrameSendQueue) == NULL)
				return -1;
			QUEUE_Frame_Write(handle->ptFrameQueue,&(handle->FrameSendQueue,1));

			return	sret ;
		}
		else
		{
			ret = 0;  // no data;
		}
	}
	else if ( retval == 0 )
	{
		// timeout		
		ret = 0;
	}
	else
	{
		// error		
		ret = -1;
	}
	
	return	ret;
}

2、线程B读取队列数据,给其他模块使用
ret = QUEUE_Frame_ReadData(handle->ptFrameQueue,&(handle->FrameRcvQueue),1);
if(ret < 0)
{
	usleep(1000);
	continue;
}
else
{
	.......
	解读数据
	.......
}

总结
代码中有一个,*PtFrame = *Frame,方法是通过指针,速度很快
通过指针指向一个结构体,便可以,实现快速赋值,复制数据

struct data1,data2
struct pdata1,pdata2
pdata1 = data1;
pdata2 = data2;
*pdata1 = *pdata2;

我的另一篇,有分析这块的用法,https://editor.csdn.net/md/?articleId=141191634

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值