linux中消息队列kfifo和信号量sem_t的用法
程序员文章站
2022-07-14 16:30:16
...
使用kfifo和sem_t配合来实现消息队列:由sem来管理目前可以发送和接收的总的消息数,由kfifo来存储消息。具体实现起来就是定义信号量sem_t_send和sem_t_recv,sem_t_send设为max_num,sem_t_recv设为0。
消息发送前先判断sem_t_send是否为0,不为0就把sem_t_send减1,,然后将消息加入kfifo队列,同时将sem_t_recv加1代表队列有1条可接收的消息。
消息接收前先判断sem_t_recv是否为0,如果不为0,则sem_t_recv减1,然后将消息从kfifo队列中取出来,同时将sem_t_send加1代表发送队列又多了一条可以发送的消息。
这里涉及了典型的设计模式:生产者消费者模式,代码结构见下文
首先我们可以定义队列结构体用来管理消息队列:
typedef struct _ST_SCLR_OS_QUEU
{
struct kfifo stFifo;//存储消息
struct semaphore stSemSend;//管理send消息
struct semaphore stSemRecv;//管理recv消息
spinlock_t stSpinLock;//消息自旋锁
u16 u16MsgSize;
u16 u16MaxNum;
bool b8Valid;
} ST_SCLR_OS_QUEUE;
//创建队列
void *OS_SHL_QueueCreate( u16 u16MsgSize, u16 u16MaxNum, const c8 *pc8Name )
{
ST_SCLR_OS_QUEUE *pstQ;
//1 创建pstQ
pstQ = (ST_SCLR_OS_QUEUE*)vk_kmalloc(sizeof(ST_SCLR_OS_QUEUE),GFP_KERNEL);
//2 初始化fifo
iret = kfifo_alloc(&( pstQ->stFifo ), u16MsgSize*u16MaxNum, GFP_KERNEL);
//3 初始化sem和lock
//semSend设置MaxNum即目前可发送的消息总数为MaxNum
vk_sema_init( &( pstQ->stSemSend ), ( int )u16MaxNum );
//semRecv设置为0即目前可接受的消息总数为0
vk_sema_init( &( pstQ->stSemRecv ), 0 );
vk_spin_lock_init( &( pstQ->stSpinLock ) );
}
//发送消息
bool OS_SHL_QueueSend(void *pQueue, void *pMsg, u16 u16MsgSize, u32 u32TimeoutInMS )
{
pstQ = ( ST_SCLR_OS_QUEUE * )pQueue
//1 获取semSend看看是否可以发送消息
if ( u32TimeoutInMS == 0 )//立即获取,没有就返回失败
{
iret = vk_down_trylock( &( pstQ->stSemSend ) );
}
else if ( u32TimeoutInMS != OS_SHL_SEMAPHORE_TIMEOUT_NEVER )//等待几秒
{
iret = vk_down_timeout( &(pstQ->stSemSend), vk_msecs_to_jiffies(u32TimeoutInMS) );
}
else//阻塞线程直到获取到
{
iret = vk_down_interruptible( &(pstQ->stSemSend) );
}
//2 将消息放进队列
iret = kfifo_in( &(pstQ->stFifo), pMsg, u16MsgSize, &(pstQ->stSpinLock) );
//3 给semRecv加1 代表队列现在可以接受的消息数多了一个
vk_up( &(pstQ->stSemRecv) );
}
//接收消息
bool OS_SHL_QueueRecv (void *pQueue, void *pMsg, u16 u16MsgSize, u32 u32TimeoutInMS )
{
pstQ = ( ST_SCLR_OS_QUEUE * )pQueue
//1 获取semRecv看看是否可以接收消息
if ( u32TimeoutInMS == 0 )//立即获取,没有就返回失败
{
iret = vk_down_trylock( &(pstQ->stSemRecv) );
}
else if ( u32TimeoutInMS != OS_SHL_SEMAPHORE_TIMEOUT_NEVER ) //等待几秒
{
iret=vk_down_timeout( &(pstQ->stSemRecv),vk_msecs_to_jiffies(u32TimeoutInMS) );
}
else//阻塞线程直到获取到
{
iret = vk_down_interruptible( &(pstQ->stSemRecv) );
}
//2 将消息取出消息队列
iret = kfifo_out ( &(pstQ->stFifo), pMsg, u16MsgSize, &(pstQ->stSpinLock) );
//3 给semSent加1 代表队列现在可以发送给的消息数多了一个
vk_up( &(pstQ->stSemSend) );
}
上一篇: POI向word添加图片,表格
下一篇: iphone向Web服务器发送图片