我正在编写一个程序,我在 while (1) 循环中运行,该循环在 select 调用上阻塞。我的程序侦听多个客户端连接的服务器套接字。我还连接到不同的服务器套接字。所以,我既充当客户端又充当服务器。
它是基于事件的设计,仅作用于在其套接字上接收到的事件/消息。到目前为止一切顺利。
这个设计有效,到目前为止我没有遇到任何问题。
我的问题是,根据我在套接字上收到的一些消息,我调用了一个函数 foo ,该函数在 for 循环中运行,并执行一些占用大量时间(例如 40-50 秒)的工作。现在,当我这样做时,我不会回到 while (1) 循环,在该循环中我被阻塞在 select 调用上。在这 40-50 秒期间,我不会对在其他套接字上收到的任何消息/事件采取行动。
有没有办法打破我的 foo 函数,以便我只处理它的一部分,然后返回到我的 while (1) 循环,检查套接字,如果那里没有任何内容,则继续处理 foo() 函数。我的问题是,如果套接字上没有任何内容,那么套接字调用将被阻止,我将无法处理 foo()。
我无法在 select 中使用时间参数,因为我已经将其用于其他一些功能?
编辑:这是一个正常的设计,让主循环在 while (1) 循环中运行,该循环仅在 select 调用上被阻止,并根据它在连接到的不同套接字上收到的消息执行不同的操作?
这里通常的方法是在线程中运行
foo()
- 这样它就独立于循环。循环只是启动线程。
您应该做的是在某个地方注意到线程当前正在运行,或者有人可能会发送大量“启动”消息,这将导致您的服务器启动越来越多的线程,直到它死亡。
另一种选择是将“等待命令”循环拆分为一个函数,该函数仅执行单个选择并处理您可能已经获得的单个命令以及一个无限调用此新函数的循环。
这样,您就可以时不时地使用
foo()
中的所有新“一次完成”功能。
您应该创建一个线程来运行您的函数,而
select
将继续等待事件。
如果没有线程,暂停和恢复进程会很复杂,但您可以像计算机一样做到这一点:在退出时保留一些空间来存储处理的上下文
foo
。在下一次调用时,它将检查要在上下文中处理的数据。关于“时间参数”我猜你正在谈论
select
超时。它可用于不同的事件,但您必须计算出来,即计算您正在侦听的所有事件的最小超时(如果您处于无限循环中,则必须在每个循环上重新计算它)。
最好的解决方案是启动一个新线程(甚至
fork
关闭新进程)。
如果您不想这样做,您可以在有工作要做时将您的选择更改为非阻塞。您还需要定期致电您的选择。
int mySelectHandler(); // Returns false if SELECT would block
// Main loop
while (1) {
mySelectHandler(); // Check for new connections and messages
}
int bigWork() {
int prevStatus = <current select status, blocking or non-blocking>;
setStatus(NONBLOCKING);
for (<some condition)) {
<do some work>
while (mySelectHandler()) // Check for new connections and messages
;
}
setStatus(prevStatus);
}
此方法有一个警告:如果在第一次调用结束之前第二次调用 bigWork(),则第一次调用将被延迟,直到第二次调用被处理为止。