首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用epoll分割故障

使用epoll分割故障
EN

Stack Overflow用户
提问于 2019-01-14 23:11:53
回答 2查看 696关注 0票数 2

我正在尝试编写一个执行以下操作的程序:

作为命令行参数,它接收FIFO文件的路径。它应该使用epoll应用程序接口来监控这些FIFO。通过FIFO,可以保证只发送浮点数。程序的输出应该是通过每个FIFO发送的数字的总和(当写入端关闭所有文件时,程序停止)。

在我开始实际的代码之前,这里有一个宏和一个你将在整个程序中看到的函数:

代码语言:javascript
复制
#define iAssert(cond, msg) crash(cond, msg, __LINE__)
void crash(bool cond, char * msg, int line){
    if(!cond){
        perror(msg);
        fprintf(stderr, "at line %d\n", line);
        exit(EXIT_FAILURE);
    }    
}

这只是一个简单的断言机制,与问题本身无关。

无论如何,首先我获取通过命令行参数传递的FIFO的数量,并创建一个epoll文件描述符:

代码语言:javascript
复制
int numFifos = argc - 1;
int epollFileDesc = epoll_create(1);
iAssert(-1 != epollFileDesc, "epoll_create");

然后,我创建了一个fifo文件描述符数组和一个sum数组,在下面的循环中,我将它们初始化为零。

代码语言:javascript
复制
 int * fifoFileDescriptors = malloc(numFifos * sizeof(int));
 iAssert(NULL != fifoFileDescriptors, "malloc1");

 float * localSums = malloc(numFifos * sizeof(float));
 iAssert(NULL != localSums, "malloc 2");

到目前为止,我认为一切都很好。下面的循环除了初始化sum数组之外,还打开FIFO,填充前面的文件描述符和寄存器事件数组。

代码语言:javascript
复制
for(int i = 0; i<numFifos; i++){
        localSums[i] = 0.f;

        int thisFd = open(argv[i+1], O_RDONLY | O_NONBLOCK);
        iAssert(-1 != thisFd, "open");

        fifoFileDescriptors[i] = thisFd;

        FILE * thisFs = fdopen(thisFd, "r");
        iAssert(NULL != thisFs, "fdopen");
        DataPass registerThis;

        registerThis.fifoIndex = i;
        registerThis.file = thisFs;

        struct epoll_event thisEvent;
        thisEvent.events = 0;
        thisEvent.events |= EPOLLIN;
        thisEvent.data.ptr = (void *)&registerThis;

        iAssert(-1 != epoll_ctl(epollFileDesc, EPOLL_CTL_ADD, thisFd, &thisEvent), "epoll_ctl");
    }

DataPass结构如下所示:

代码语言:javascript
复制
typedef struct{
    int fifoIndex;
    FILE * file;
}DataPass;

正如您所看到的,我想要的是接收文件流,而不是文件描述符,因为它们更容易读取。除此之外,我保留了FIFO的索引,这样我就知道哪一个是它了。

在此之后,我监视是否有变化:

代码语言:javascript
复制
int nOpen = numFifos;

    struct epoll_event events[MAX_EVENTS];

    while(nOpen){
        int active = epoll_wait(epollFileDesc, events, MAX_EVENTS, -1); 
        iAssert(-1 != active, "epoll_wait");

        for(int i = 0; i<active; i++){
            struct epoll_event thisEvent = events[i];


            if(thisEvent.events & EPOLLIN){
                DataPass * thisData = (DataPass *)thisEvent.data.ptr;
                //fifo with index thisData->fifoIndex has sent a message
                float x;
                while(1 == fscanf(thisData->file, "%f", &x)){
                    localSums[thisData->fifoIndex] += x;
                }

            }else if (thisEvent.events & (EPOLLERR | EPOLLHUP)){
                //need to close this connection
                DataPass * thisData = (DataPass *)thisEvent.data.ptr;
                iAssert(-1 != epoll_ctl(epollFileDesc, EPOLL_CTL_DEL, fifoFileDescriptors[thisData->fifoIndex], NULL), "epoll_ctl del");
                fclose(thisData->file);
                close(fifoFileDescriptors[thisData->fifoIndex]);
                nOpen--;
            }
        }
    }

MAX_EVENTS宏定义为4。

在运行这段代码(并使用辅助程序创建fifos并通过它们发送值)之后,我得到了一个分段错误,我设法跟踪到了fscanf部分。即使我已经追踪到了它,我仍然不知道它为什么会导致它。

有什么想法吗?

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-01-16 07:11:47

这一行:

代码语言:javascript
复制
DataPass registerThis;

在堆栈上声明一个结构。只要你再次循环,这个内存就会被一个新的结构覆盖。然后你会得到一个指向它的指针:

代码语言:javascript
复制
thisEvent.data.ptr = (void *)&registerThis;

循环结束后,此指针不会指向任何有意义的内容。

要解决此问题,您需要在堆上分配该结构。

票数 1
EN

Stack Overflow用户

发布于 2019-01-16 07:10:36

通过将指向局部变量的指针保存到其所在堆栈的有效性之后,您将调用未定义的行为

代码语言:javascript
复制
for(int i = 0; i<numFifos; i++){
        DataPass registerThis;
        registerThis.file = thisFs;
        thisEvent.data.ptr = (void *)&registerThis;
}

不要导出指向局部变量的指针,并在它们不再存在时尝试使用它们。以更持久的方式分配您的存储空间。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54207983

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档