这更多是一种观察,也是对处理这种情况的最佳方法的建议。
我有两个线程,一个只是泵入数据,另一个接收数据并在发送另一个套接字之前做很多工作。两个线程都通过域套接字连接。这里使用的协议是 UDP。我不想使用 TCP,因为它是基于流的,这意味着如果队列中的空间很小,我的数据就会被拆分和发送。这很糟糕,因为我正在发送不应该拆分的数据。因此我使用了 DGRAM。有趣的是,当发送线程通过抽取如此多的数据压倒了接收线程时,在某些时候域套接字缓冲区被填满并且 sendto() 返回 ENOBUFS。我认为如果发生这种情况, sendto() 将阻塞,直到缓冲区可用。这将是我想要的行为。然而,情况似乎并非如此。我以一种相当奇怪的方式解决了这个问题。
CPU Yield 方法 如果我得到 ENOBUFS,我会执行 sched_yield(); 因为 OSX 中没有 pthread_yield() 。之后,我尝试再次重新发送。如果失败了,我会继续做同样的事情,直到它被采取。这很糟糕,因为我只是在做一些无用的事情而浪费 CPU 周期。如果 sendto() 被阻止,我会很高兴。
睡眠方法我尝试使用 sleep(1) 而不是 sched_yield() 来解决相同的问题,但这没有用,因为 sleep() 会使我的进程进入睡眠状态,而不仅仅是发送线程。
他们两个似乎都不适合我,而且我已经没有选择了。有人可以建议处理这个问题的最佳方法是什么吗?是否有一些我不知道的巧妙技巧可以减少不必要的 CPU 周期?顺便说一句,根据这个讨论http://lists.freebsd.org/pipermail/freebsd-hackers/2004-January/005385.html ,手册页上关于 sentto() 的内容是错误的
内核中的 Upd 代码:
The udp_output function in /sys/netinet/udp_usrreq.c, seems clear:
/*
* Calculate data length and get a mbuf
* for UDP and IP headers.
*/
M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
if (m == 0) {
error = ENOBUFS;
if (addr)
splx(s);
goto release;
}