我可以反复切换阻塞和非阻塞行为吗?

3
我有两个进程通过Unix域套接字进行主/副本设置的通信。副本需要定期询问主要指导,但仅在主要指示已准备好提供所需指导时才应如此。如果主要准备就绪,则副本应查询主要并等待响应;否则,它应继续执行当前任务。
通常,我会使用POSIX信号量向副本通信,以告知其主要是否准备就绪-这很快速且轻量级。不幸的是,我正在研究不支持POSIX共享内存的系统上工作。因此,Unix套接字是我唯一拥有的。
我知道非阻塞读取非常快,所以我想知道是否可以这样做:
1. 在副本和主之间建立连接。 2. 将副本端设置为非阻塞。 3. 定期检查副本是否可以从主读取。 4. 如果读取成功,请将套接字切换到阻塞状态并查询主要。完成查询后,请将套接字返回到非阻塞状态。 5. 如果读取失败,请继续直到下一次检查。
我能否反复在阻塞和非阻塞行为之间切换套接字?

1
既然是套接字,为什么不直接使用recv(descriptor, buffer, length, MSG_DONTWAIT)进行非阻塞读取,而使用recv(descriptor, buffer, length, 0)进行阻塞读取呢?同样地,对于send(descriptor, buffer, length, MSG_DONTWAIT | MSG_NOSIGNAL)进行非阻塞写入,而使用send(descriptor, buffer, length, MSG_NOSIGNAL)进行阻塞写入。 - Nominal Animal
1
通常,这种问题可以使用“select”进行管理。阅读“select”的文档,您将能够找到一个干净的程序架构。 - Marian
@Marian:啊,只需在不超时和无限超时之间切换即可。我在主要部分的其他部分中一直在使用select / epoll,为什么我没有想到呢?请考虑将其提交为答案。谢谢!! - tonysdg
@NominalAnimal:这也是一个很棒的建议——我不知道MSG_DONTWAIT标志。 - tonysdg
2个回答

2

You can using fcntl:

int file_descriptor;
int flags;

// open file_descriptor

flags = fcntl(file_descriptor, F_GETFL, 0);
flags &= ~O_NONBLOCK;           // set blocking
flags |= O_NONBLOCK;            // set non-blocking
fcntl(file_descriptor, F_SETFL, flags);

但是我认为如果您只使用两个套接字,您的程序将更加简单。一个用于控制(非阻塞),另一个用于数据(阻塞)。使用控制套接字传递“就绪”/“未就绪”消息,使用数据套接字进行“指导”。这消除了不断打开/关闭套接字或重复修改其配置的需要,并应简化程序中的控制流程。它还可以将数据流和控制流分离,这通常是一个好的做法。

我原本计划保持套接字开放并在整个副本的生命周期内重复使用它,但是两个套接字的想法确实很有趣。我没有考虑过分离数据/控制 - 这非常有道理! - tonysdg
关于您的编辑:我能反复切换吗?虽然我非常喜欢双插口的想法,但这更多是出于好奇而不是其他任何原因。 - tonysdg
@tonysdg 我认为这个应该是可行的,但是我觉得套接字通信有时候会很具有挑战性。我不相信自己总能预测潜在的死锁情况,所以我更喜欢简化控制流程,并尽可能避免阻塞读取。我个人没有尝试过在打开后更改套接字的阻塞/非阻塞模式。 - skrrgwasme

2
我建议使用一个带有永久阻塞套接字的单独线程。当主线程准备好被查询时,发送一些信息。该线程会阻塞并尝试接收该信息:当它接收到信息后,发出查询等操作,然后返回最初的接收状态。 编辑 不建议将基本上非阻塞的系统切换为阻塞模式,即使是暂时的,并且即使设置了读取超时,因为系统肯定会在某个时间停止至少超时时间,具体取决于对等方和介入的网络的行为。最好将此依赖项隔离到单独的线程中。

我曾考虑过这种方法,但由于系统的研究性质,我不太愿意再次引入多线程到我的副本中。我会重新考虑我的反对意见,但出于好奇,我也想知道我描述的行为是否被允许/正确/有效。你有什么见解吗? - tonysdg
将一个基本上非阻塞的系统暂时切换到阻塞模式并设置读取超时,甚至是不明智的,因为系统肯定会在某个时间停止至少超时时间,这取决于对等方和干预网络的行为。最好将该依赖项隔离到单独的线程中。我认为“研究”不足以成为避免线程模型的动机。 - user207421
当系统的“研究”部分是仅具有有限多线程支持的操作系统时,就会出现这种情况 :-) 我不想深入探讨这些细节,但可以说这是一个学术研究项目,以各种方式束缚了我。尽管如此,我将跳过非阻塞/阻塞开关并测试单独的线程,看看它是否受支持--感谢您的见解! - tonysdg
3
如果可用,可以使用select()函数,并保持全部非阻塞。不要切换。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接