一个简易的事件队列的实现

摘要:
值得注意的是,Item是void*类型,也就是说,这个队列可以存储任何类型,因为我们实际上存储了指针。(这样描述真的可以吗?)队列的源代码。h如下/***@filequeue h*@brief**/#ifndefQUEUE_h#defineQUEUE_h#defineMAXQUEUESIZE1000typedefenseumboolean{False,True}bool;typedefvoid*项目;typedefstructQueue*QueueADT;QueueADTNewQueue;voidFreeQueue;voidEnQueue;ItemDeQueue;boolQueueIsEmpty;boolQueueIsFull;intQueueLength;ItemGetQueueItem;#endiqueue的源代码。c如下:/***@filequeue。c*@brief*/#include #include #include #include #include“queue.h”structQueue{Itemelements[MAXQUEUESIZE];intiHead;intiCount;};QueueADTNewQueue{QueueADTqueue;queue=malloc;queue-˃iHead=queue-˃iCount=0;return;}voidFreeQueue{free;}voidEnQueue{if{printf;exit(-1);}队列-˃元素[%MAXQUEUESIZE]=x;队列-˃iCount++;}ItemDeQueue{Itemresult;if{printf;exit(-1);}result=queue-˃elements[queue-˃iHead];队列-˃iHead=%MAXQUEUESIZE;队列-˃iCount--;return;}boolQueueIsEmpty{return;}boolQueueIsFull{return;}intQueueLength{return;}ItemGetQueueItem{如果{returnqueue-˃元素[%MAXQUEUESIZE];}输出函数退出(-1);}第2章:事件队列事件队列是真实队列API上的一个简单包。仅添加了DoEvent函数。
第一章:实现队列

我觉得实现一个队列还是比较有意思的事情,采用常见的循环数组实现的方式。

值得注意的是,Item项是void *类型的,也就是说这个队列可以存储任意类型,因为我们其实存储的是指针。(这么描述真的没问题吗?)

queue.h的源代码如下

/**
 * @file    queue.h
 * @brief
 * */
#ifndef QUEUE_H
#define QUEUE_H
#define
MAXQUEUESIZE 1000 typedef enum boolean{False,True} bool; typedef void * Item; typedef struct Queue * QueueADT; QueueADT NewQueue(void); void FreeQueue(QueueADT queue); void EnQueue(QueueADT queue,Item x); Item DeQueue(QueueADT queue); bool QueueIsEmpty(QueueADT queue); bool QueueIsFull(QueueADT queue); int QueueLength(QueueADT queue); Item GetQueueItem(QueueADT queue,int index); #endif

queue.c的源代码如下:

/**
 * @file    queue.c
 * @brief
 */
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include "queue.h"
struct Queue
{
    Item elements[MAXQUEUESIZE];
    int iHead;
    int iCount;
};
QueueADT NewQueue(void)
{
    QueueADT queue;
    queue = (QueueADT)malloc(sizeof(struct Queue));
    queue->iHead = queue->iCount = 0;
    return (queue);
}
void FreeQueue(QueueADT queue)
{
    free(queue);
}
void EnQueue(QueueADT queue,Item x)
{
    if(QueueIsFull(queue))
    {
        printf("QueueIsFull
");
        exit(-1);
    }
    queue->elements[(queue->iHead+queue->iCount)%MAXQUEUESIZE] = x;
    queue->iCount++;
}
Item DeQueue(QueueADT queue)
{
    Item result;
    if(QueueIsEmpty(queue))
    {
        printf("QueueIsEmpty
");
        exit(-1);
    }
    result = queue->elements[queue->iHead];
    queue->iHead = (queue->iHead + 1)%MAXQUEUESIZE;
    queue->iCount--;
    return (result);
}
bool QueueIsEmpty(QueueADT queue)
{
    return (queue->iCount == 0);
}
bool QueueIsFull(QueueADT queue)
{
    return (queue->iCount == MAXQUEUESIZE);
}
int QueueLength(QueueADT queue)
{
     return (queue->iCount);
}
Item GetQueueItem(QueueADT queue,int index)
{
    if(index >= 0 && index < QueueLength(queue))
    {
        return queue->elements[(queue->iHead + index)%MAXQUEUESIZE];
    }
    printf("index < 0 or index > queue length
");
    exit(-1);
}
第二章:事件队列

事件队列实在队列API上做一个简单的封装。

只是添加了一个DoEvent(QueueADT queue)函数。

Event.h

#ifndef MY_EVENT_H
#define MY_EVENT_H
#include "queue.h"
#define NewEventQueue() NewQueue()
typedef struct Event * Event_ptr;
void FreeEventQueue(QueueADT queue,void(*FreeEventNode)(Event_ptr x));
void EnEventQueue(QueueADT queue,void (* pEvent)(void * argument),void * argument, size_t size);
void DoEvent(QueueADT queue);
#endif // MY_EVENT_H

Event.c

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "Event.h"
#include <string.h>
typedef struct Event
{
    void (* pEvent)(void * argument);
    void * argument;
}Event;
inline static void QuitIfPtrIsNULL(void * ptr,const char * message)
{
    if(ptr == NULL)
    {
        fprintf(stderr,"%s
",message);
        exit(-1);
    }
}
void FreeEventQueue(QueueADT queue,void(*FreeEventNode)(Event_ptr x))
{
    int i = 0;
    for(i = 0;i < QueueLength(queue);i++)
    {
        FreeEventNode(GetQueueItem(queue,i)); //释放单个节点malloc的内存,由用户实现
    }
    FreeQueue(queue);
}
void EnEventQueue(QueueADT queue,void (* pEvent)(void * argument),void * argument, size_t size)
{
    Event * x = NULL;
    QuitIfPtrIsNULL(queue,"queue == NULL");
    QuitIfPtrIsNULL(pEvent,"pEvent == NULL");
    x = (Event *)malloc(sizeof(Event));
    QuitIfPtrIsNULL(x,"malloc error");
    x->pEvent   = pEvent;
    x->argument = malloc(size);
    memcpy(x->argument,argument,size);
    EnQueue(queue,x);
}
void DoEvent(QueueADT queue)
{
    Event * x = NULL;
    QuitIfPtrIsNULL(queue,"queue == NULL");
    if(!QueueIsEmpty(queue))
    {
        x = DeQueue(queue);
        QuitIfPtrIsNULL(x,"some thing is wrong");
        x->pEvent(x->argument);
        free(x->argument);
        free(x);
    }
}
第三章:事件模拟

在完成底层库之后,可以进行事件模拟了,当然,由于在linux下面编程,略微风骚的扩展了下功能,用了定时器,一次检测事件,一次处理事件。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include "queue.h"
#include "Event.h"
#include "kbhit.h"
unsigned int TimerCount;
QueueADT queue;
void PrintChar(void * c)
{
    char * a = (char *)c;
    printf("
%c",*a);
}
void timefunc(int sig)      /* 定时事件代码 */
{
    if(TimerCount++ % 7 != 0)                //why I am 7,but not 2?
    {
        if(kbhit())
        {
            char c = getch();
            EnEventQueue(queue,PrintChar,&c,sizeof(c));
        }
    }
    else
    {
        DoEvent(queue);
    }
    signal(SIGPROF, timefunc);    /* 捕获定时信号 */
}
int main()
{
    queue = NewQueue();
    struct itimerval value;
    value.it_value.tv_sec       = 0;    // 定时1.5秒
    value.it_value.tv_usec      = 100000;
    value.it_interval.tv_sec    = 0;    // 定时1.5秒
    value.it_interval.tv_usec   = 100000;
    signal(SIGPROF, timefunc);     // 捕获定时信号
    setitimer(ITIMER_PROF, &value, NULL); // 定时开始
    while (1);
    return 0;
}

如上所示,假如TimerCount++ % 2 == 0 那么检测事件的频率和处理事件的频率就一样了,通过调整参数,我们可看到经典讨论下reader和writter问题。

让读者的频率加快,或者让写者的速率加快。

由于linux下面没有kbhit和getch函数,所以照搬了网上的两段代码,如下。

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
int kbhit(void)
{
    struct termios oldt, newt;
    int ch;
    int oldf;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
    fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
    ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    fcntl(STDIN_FILENO, F_SETFL, oldf);
    if(ch != EOF)
    {
        ungetc(ch, stdin);
        return 1;
    }
    return 0;
}

int getch(void)
{
    struct termios oldt,newt;
    int ch;
    tcgetattr( STDIN_FILENO, &oldt );
    newt = oldt;
    newt.c_lflag &= ~( ICANON | ECHO );
    tcsetattr( STDIN_FILENO, TCSANOW, &newt );
    ch = getchar();
    tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
    return ch;
}
检验发现,实现的也不是特别好。

免责声明:文章转载自《一个简易的事件队列的实现》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Oracle函数之LISTAGGQt Access violation code c0000005 debug write access violation下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

eureka服务列表刷新设置

服务器:当我们启用服务使用者时,它将向服务注册中心发送一个rest请求,以获取上面注册的服务列表。出于性能原因,eureka服务器将维护一个只读缓存服务列表以返回到客户端。默认情况下,缓存列表将每30秒更新一次。如果关闭UseReadOnlyResponseCache,服务器:#将不会读取只读缓存服务列表,因为每30秒刷新一次很慢,所以读/写缓存过期策略Us...

索引节点(inode)爆满问题处理

后来,我用df-I检查/data分区的索引节点,发现它已满,这导致系统无法创建新的目录和文件。inode是用于存储这些数据的信息,包括文件大小、所有者、用户组、读写权限等。inode索引每个文件的信息,因此它具有inode的值。根据指令,操作系统可以通过inode值最快找到对应的文件。故障排除的原因是/data/cache目录中有大量小字节缓存文件,这些文件...

【转载】SecureCRT配色推荐和永久设置

2.配置文件夹和其他颜色选项==“全局选项==”终端==“外观==”ANSI颜色单击第二行中的第五个色块以修改文件夹颜色:对第二个色块执行相同的操作以修改压缩包和jar包的颜色:如果设置后文件夹和其他的颜色无效,您可以对第二行中设置背景色和字体颜色的颜色块执行相同的操作!...

xcode模拟器不显示键盘解决方案

当我们使用Xcode进行开发时,我们并不总是需要在iPhone上运行代码。有时模拟器可以解决这些问题。但当你使用模拟器时,你会发现,如果你使用模拟器上的键盘在TextFiled中输入信息,这是可以的,但如果你使用键盘输入信息,那么你会发现模拟器上的屏幕将不再显示。这是因为默认情况下,xcode使用计算机键盘作为外部键盘,不会弹出虚拟键盘。...

Cesium深入浅出之视频投影【转】

通常,我们使用矩形,因为视频形状是方形的。据怀疑,视频标签隐藏了这段关系。如果再次显示,视频将再次移动。此处使用VideoSynchronizer。它可以使视频元素与铯的模拟时钟同步。让我们看看它的构造函数:name type description optionsObject option子属性:name type默认值description用于驱动视频的...

docker run hangs问题排查记录

1.故障描述过去两天遇到了一个非常奇怪的问题。现在完整的故障描述如下:1)首先,我的同事告诉我,K8S集群中的一个工作节点将其状态更改为NoReady,并且在节点kubelet_truntime的错误日志中发现了大量此类日志E060301:50:51.45511776268remote。go:332]ExecSync1f0e3ac13faf224129bc4...