如何在循环中等待两种类型的事件(C)?
How to wait for 2 types of events in a loop (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
的联机帮助页:
WNOHANG - return immediately if no child has exited.
因此,如果 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 的答案也应该有效。
思路很简单,不是让waitpid
和read
函数一直等待,除非它们耗费一些时间来完成它们的操作。这个想法是保持超时机制,这样,如果 waitpid
对整个操作没有任何影响,它会立即 return 并且同样的事情也适用于读取操作。
如果 read
函数读取整个缓冲区需要很长时间,您可以从 read
函数中手动限制读取,这样它就不会一次读取整个缓冲区,而是它读取 2 毫秒,然后将循环传递给 waitpid
函数执行。
但是为您的目的使用线程是安全的,而且它很容易实现。 Here's a nice guideline 关于如何实现线程。
在您的情况下,您需要声明两个线程。
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
。两者本质上都在做同样的工作。它们允许 select 那些有输入可用的描述符。因此,例如,您可以同时等待两个套接字。但是,它不能直接用于您的情况,因为您要等待进程和套接字。解决方案是创建一个管道,在 waitpid 完成时接收一些东西。
您可以启动一个新线程,并用管道将它与原来的线程连接起来。新线程将调用 waitpid
并在完成后将其结果写入管道。主线程将使用 select
.
等待套接字或管道
我试图在 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
的联机帮助页:
WNOHANG - return immediately if no child has exited.
因此,如果 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 的答案也应该有效。
思路很简单,不是让waitpid
和read
函数一直等待,除非它们耗费一些时间来完成它们的操作。这个想法是保持超时机制,这样,如果 waitpid
对整个操作没有任何影响,它会立即 return 并且同样的事情也适用于读取操作。
如果 read
函数读取整个缓冲区需要很长时间,您可以从 read
函数中手动限制读取,这样它就不会一次读取整个缓冲区,而是它读取 2 毫秒,然后将循环传递给 waitpid
函数执行。
但是为您的目的使用线程是安全的,而且它很容易实现。 Here's a nice guideline 关于如何实现线程。
在您的情况下,您需要声明两个线程。
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
。两者本质上都在做同样的工作。它们允许 select 那些有输入可用的描述符。因此,例如,您可以同时等待两个套接字。但是,它不能直接用于您的情况,因为您要等待进程和套接字。解决方案是创建一个管道,在 waitpid 完成时接收一些东西。
您可以启动一个新线程,并用管道将它与原来的线程连接起来。新线程将调用 waitpid
并在完成后将其结果写入管道。主线程将使用 select
.