UDP - потеря данных во время микровзрывов - PullRequest
2 голосов
/ 12 июля 2011

Код ниже работает отлично (т.е. не пропускает сообщения) в 99,9 раз.Но когда между дейтаграммами поступает микросхема дейтаграмм со скоростью 2-3 микросекунды, я испытываю потерю данных.Для вызова функции boost notify_one () требуется от 5 до 10 микросекунд, так что сам по себе является ключевым узким местом в этих условиях.Любые предложения о том, как улучшить производительность?

Поток кода получателя / "производителя":

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);
}

Ответы [ 4 ]

2 голосов
/ 13 июля 2011

Просто измените

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

на

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

Таким образом, пакеты не должны пробуждать поток для обработки, если поток уже активен и занятпосмотрите новый пакет перед сном.

Хорошо, это не так просто, потому что вам нужно снять блокировку между пакетами, но идея сработает - перед сном проверьте, пуста ли очередь.*

1 голос
/ 12 июля 2011

Ваш очевидный засор находится в кондиционировании. Ваша главная надежда будет в использовании реализации без блокировки Q. Это, вероятно, очевидное утверждение для вас. Разумеется, единственный способ заставить работать без блокировки q - это использовать многоядерные процессоры и не против посвятить себя выполнению задачи.

1 голос
/ 12 июля 2011

Если вы теряете данные, попробуйте увеличить размер чтения буфера сокета.Если вы используете boost :: asio, посмотрите на эту опцию: boost::asio::socket_base::receiver_buffer_size.Как правило, для наших приложений UDP с высокой пропускной способностью мы устанавливаем размер буфера сокета равным 1 МБ (в некоторых случаях больше).

Кроме того, убедитесь, что буферы, которые вы используете в своих принимающих вызовах, не слишком велики, они должны быть достаточно большими, чтобы обрабатывать ваш максимальный ожидаемый размер датаграммы (который, очевидно, зависит от реализации).

0 голосов
/ 13 июля 2011

Некоторые общие предложения:

  • Увеличение размера буфера приема сокета.
  • Считать все доступные дейтаграммы и передать их для обработки.
  • Избегайте копирования данных, передайте указатели.
  • Уменьшите область блокировки до абсолютного минимума, скажем, только нажмите / выдвиньте указатель на / из очереди под этим мьютексом.
  • Если все вышеперечисленное не сработало, посмотрите на структуры данных без блокировки, чтобы передать данные.

Надеюсь, это поможет.

...