如何在循环中等待两种类型的事件(C)



我试图在while-true循环中等待waitpid()read()。具体来说,我正在等待这两个事件中的任何一个,然后在循环的每次迭代中对其进行处理。目前,我有以下实现(我不希望这)。

while (true) {
  pid_t pid = waitpid(...);
  process_waitpid_event(...);
  ssize_t sz = read(socket, ....);
  process_read_event(...);
}

此实现的问题是第二事件的处理取决于第一个事件的完成。我希望不再处理这两个事件,而是希望处理循环的每次迭代中首先发生的任何事件。我应该怎么做?

如果您不想触摸线程,则可以将其包含在waitpid的调用选项中:

pid_t pid = waitpid(pid, &status, WNOHANG);

waitpid的manpage中:

wnohang-如果没有孩子退出,请立即返回。

因此,如果waitpid还没有准备好,它将不会阻止,并且该程序将继续进入下一行。

至于read,如果它阻止了您,您可能想看看poll(2)。您可以从本质上检查一下您的套接字是否准备就绪,例如250ms,然后在当时致电read。这将允许它不阻止。

您的代码看起来有点像这样:

// Creating the struct for file descriptors to be polled.
struct pollfd poll_list[1];
poll_list[0].fd = socket_fd;
poll_list[0].events = POLLIN|POLLPRI;
// POLLIN  There is data to be read
// POLLPRI There is urgent data to be read
/* poll_res  > 0: Something ready to be read on the target fd/socket.
** poll_res == 0: Nothing ready to be read on the target fd/socket.
** poll_res  < 0: An error occurred. */
poll_res = poll(poll_list, 1, POLL_INTERVAL);

这只是假设您是从套接字中的read,从代码中的变量名来判断。正如其他人所说的那样,您的问题可能需要一些更重的重型。

,如果您不想在程序中使用线程,@DanielPorteous的答案也应起作用。

这个想法很简单,除非他们花了一些时间来执行操作,否则不让waitpidread功能等待。这个想法是保持超时机制,以便,如果waitpid对整个操作没有影响,它将立即返回,并且读取操作也会发生同样的事情。

如果read功能需要很长时间才能读取整个缓冲区,则可以从read函数手动限制读数,以免一次读取整体,而是读取2毫秒,然后传递周期到执行waitpid函数。

但是可以安全地用于您的目的,并且非常易于实现。这是关于如何实现线程的好指南。

在您的情况下,您需要声明两个线程。

pthread_t readThread;
pthread_t waitpidThread;

现在您需要创建线程并将特定函数作为其参数传递。

pthread_create(&(waitpidThread), NULL, &waitpidFunc, NULL);
pthread_create(&(readThread), NULL, &readFunc, NULL);

现在,您可能必须编写waitpidFuncreadFunc功能。他们看起来像这样。

void* waitpidFunc(void *arg)
{
    while(true) {
        pid_t pid = waitpid(...);
        // This is to put an exit condition somewhere. 
        // So that you can finish the thread
        int exit = process_waitpid_event(...);
        if(exit == 0) break;
    }
    return NULL;
}

我认为在这种情况下的正确工具是selectpoll。两者都在做同样的工作。他们允许选择可用输入的那些描述符。因此,例如,您可以在两个插座上同时等待。但是,在您的情况下,它不能直接使用,因为您想等待流程和套接字。解决方案将是创建一个管道,该管道将在等待夹完成时会收到一些东西。

您可以启动一个新线程,并将其与原始螺纹一起使用管道连接。新线程将调用waitpid,完成后,它将将其结果写入管道。主线程将使用select等待插座或管道。

最新更新