2011-07-12 89 views
2

下面的代码运行很好(即不丢弃消息)99.9的时间。但是,当数据报以微秒为单位在数据报之间以2-3微秒的速率进入时,我会遇到数据丢失。 boost notify_one()成员调用需要5到10微秒才能完成,因此在这些条件下它本身就是关键瓶颈。有关如何提高性能的任何建议?UDP - 在microbursts期间丢失数据

接收机/ “生产者” 代码螺纹:

if (bytes_recvd > 0) { 
    InQ.mut.lock(); 
    string t; 
    t.append(data_, bytes_recvd); 
    InQ.msg_queue.push(t); // < 1 microsecs 
    InQ.mut.unlock(); 
    InQ.cond.notify_one(); // 5 - 10 microsecs 
} 

消费者代码线程:

//snip...... 
std::string s; 
while (1) { 
    InQ.mut.lock(); 
    if (!InQ.msg_queue.empty()) { 
     s.clear(); 
     s = InQ.msg_queue.front(); 
     InQ.msg_queue.pop(); 
    } 
    InQ.mut.unlock(); 
    if (s.length()) { 
     processDatagram((char *)s.c_str(), s.length()); 
     s.clear(); 
    } 
    boost::mutex::scoped_lock lock(InQ.mut); 
    InQ.cond.wait(lock); 
} 
+1

在linux中,你可以增加每个套接字的数据包的内核缓冲区,所以你不会丢失它们,我想你也可以在windows上做到这一点。 –

+5

UDP作为标准不能保证传送。如果你想保证交付,使用TCP/IP。 – mjr

+0

只是因为你使用UDP并不意味着你高兴地丢失了数据包。 –

回答

1

如果你丢失数据尝试增加套接字缓冲区读取大小。如果您使用boost :: asio,请查看此选项:boost::asio::socket_base::receiver_buffer_size。通常,对于我们的高吞吐量UDP应用程序,我们将套接字缓冲区大小设置为1MB(在某些情况下更多)。另外,请确保您在接收调用中使用的缓冲区不是太大,它们应该只足够大以处理您的最大预期数据报大小(这显然取决于实现)。

1

你明显的堵塞是在调理。 您的主要希望是使用无锁Q实现。这可能是对你的一个明显的陈述。 真正让无锁q为你工作的唯一方法当然是如果你有多核心并且不介意专注于消费任务。

2

只要改变

if (!InQ.msg_queue.empty()) { 

while (!InQ.msg_queue.empty()) { 

这样的分组不必唤醒线程得到处理,如果线程已经醒了,忙,它会看到新睡前包。

好吧,这不是那么简单,因为你需要释放数据包之间的锁定,但这个想法将起作用 - 在睡觉之前,检查队列是否为空。

0

一些一般性的建议:

  • 增加套接字接收缓冲区大小。
  • 阅读所有可用的数据报,然后将它们全部传递进行处理。
  • 避免数据复制,传递指针。
  • 将锁定范围降至绝对最小值,例如,只将指针推入/弹出该互斥锁下的队列中/退出队列。
  • 如果以上所有都失败,请查看无锁数据结构以传递数据。

希望这会有所帮助。

+0

所有这些建议让我充满希望。但是有一个问题,因为我使用boost的async_receive_from(),我该如何使用它来读取所有可用的数据报? –

+0

我不知道'asio'那么好。一般来说,你可以将套接字设置为非阻塞状态并阅读,直到获得'EWOULDBLOCK'。 –

+0

我会研究如何/如何可以使用asio和async_receive_from()完成。 –