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

如何在循环(C)中等待两种类型的事件?,c,linux,events,concurrency,condition-variable,C,Linux,Events,Concurrency,Condition Variable,我试图在中等待waitpid()和read()。具体地说,我正在等待这两个事件中的任何一个,然后在循环的每个迭代中处理它。目前,我有以下实现(这不是我想要的) 此实现的问题在于,第二个事件的处理取决于第一个事件的完成。我不希望按顺序处理这两个事件,而是希望处理循环每次迭代中最先出现的事件。我该怎么做 如果不想接触线程,可以在调用waitpid的选项中包括: pid_t pid = waitpid(pid, &status, WNOHANG); 从waitpid的手册页开始: pid_t

我试图在
中等待
waitpid()
read()。具体地说,我正在等待这两个事件中的任何一个,然后在循环的每个迭代中处理它。目前,我有以下实现(这不是我想要的)


此实现的问题在于,第二个事件的处理取决于第一个事件的完成。我不希望按顺序处理这两个事件,而是希望处理循环每次迭代中最先出现的事件。我该怎么做

如果不想接触线程,可以在调用
waitpid
的选项中包括:

pid_t pid = waitpid(pid, &status, WNOHANG);
waitpid
的手册页开始:

pid_t pid = waitpid(pid, &status, WNOHANG);
WNOHANG-如果没有孩子退出,请立即返回

因此,如果
waitpid
没有准备好,它将不会阻塞,程序将继续运行到下一行

至于
读取
,如果它被阻塞,您可能需要查看
轮询(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);
//为要轮询的文件描述符创建结构。
结构pollfd poll_list[1];
轮询列表[0]。fd=socket\u fd;
轮询列表[0]。事件=POLLIN | POLLPRI;
//有数据要读取
//POLLPRI有紧急数据需要读取
/*poll_res>0:准备在目标fd/套接字上读取的内容。
**poll_res==0:没有准备好在目标fd/套接字上读取的内容。
**poll_res<0:发生错误*/
poll_res=poll(poll_list,1,poll_INTERVAL);

这只是假设从代码中的变量名判断,您正在从套接字读取。正如其他人所说,您的问题可能需要一些更繁重的任务,比如线程。

如果您不想在程序中使用线程,@DanielPorteous的答案也应该有效

这个想法很简单,不需要保持
waitpid
read
函数等待,除非它们花费一些时间来执行操作。我们的想法是保留一个超时机制,这样,如果
waitpid
对整个操作没有任何影响,它将立即返回,读取操作也会如此

如果
read
函数读取整个缓冲区需要很长时间,您可以手动限制
read
函数的读取,使其不会一次读取整个缓冲区,而是读取2毫秒,然后将循环传递给
waitpid
函数执行

但是,它可以安全地为您的目的使用线程,而且非常容易实现。关于如何实现线程

在本例中,需要声明两个线程

pthread_t readThread;
pthread_t waitpidThread;
现在需要创建线程并传递特定函数作为其参数

pthread_create(&(waitpidThread), NULL, &waitpidFunc, NULL);
pthread_create(&(readThread), NULL, &readFunc, NULL);
现在您可能需要编写
waitpidFunc
readFunc
函数。它们可能看起来像这样

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;
}

我认为在这种情况下,正确的工具是
select
poll
。两者的工作基本相同。它们允许选择输入可用的描述符。因此,例如,您可以同时在两个套接字上等待。但是,它在您的情况下不能直接使用,因为您需要等待进程和套接字。解决方案是创建一个管道,当waitpid完成时,它将接收一些东西


您可以启动一个新线程,并使用管道将其与原始线程连接。新线程将调用
waitpid
,完成后将结果写入管道。主线程将使用
选择

等待套接字或管道。您想以异步方式执行吗?这更像是线程问题。您可以搜索如何在C中实现线程。请详细说明您的问题。等待是为了什么?你在读什么。特别是,您是否只是有一个子进程,希望读取其输出,但只需要知道它何时结束?请原谅我的无知,您能将其与SIGCHLD的使用进行对比吗?您所介绍的内容似乎更为复杂,并且没有提供我所看到的任何好处。此外,目前还不清楚OP是否首先需要这类设备,很有可能他们真的有管道,只需等待管道关闭,在这一点之后,您可以等待PID以获得退出状态。您可以详细说明为什么您建议这样做而不是处理SIGCHLD吗?因为用户最初使用的是waitpid,而不是处理信号,尽管考虑到他们的程序正在等待子进程.cmon,这当然是一个有效的选项。在大多数情况下,为SIGCHLD安装处理程序并从read处理EINTR是标准的操作。所提出的解决方案的缺点在于,它向循环添加了更多的系统调用,并使线程即使在无事可做时也能唤醒。但更重要的是,OP是否有理由首先在循环中等待PID还不清楚。最有可能的是,他们只是生了一个孩子,只是想在孩子退出后停止阅读。解决方法是继续读取,直到什么都没有剩下,然后用waitpid收集退出状态。也就是说,“他们没有处理信号”听起来不是一个合理的理由。他们也没有使用投票。这里可能无法使用上述标准解决方案,您提供的代码可能会用作合理的解决方法。不幸的是,答案是在没有要求OP澄清问题的情况下给出的,与这里的其他答案类似。这一个至少不直接进入线程。不需要尖刻,我只是安装最明显的