2012-06-08 7 views
2

У меня есть проблема, которую я действительно не знаю, как решить. У меня есть программа, которая мультиплексирует несколько соединений. Эти соединения одновременно получают потоковые данные. Мне пришлось настраивать неблокирующие сокеты, поскольку потоки имеют разные битрейты. Теперь то, что я на самом деле делал, это сохранить эти сокеты в массиве, проходящем через них, и обнаружить с помощью select, если есть данные для чтения и обработки следующего элемента в массиве, если нет. Он работает очень хорошо, за исключением того факта, что процессор всегда на 100%. На самом деле, если в какой-то момент нет ничего, что можно было бы прочитать из любого сокета, он все равно будет зацикливаться. Я действительно не знаю, как можно было бы заблокировать цикл всякий раз, когда никакие данные не доступны ни в одном сокете и просто продолжаются, когда есть данные. Я думаю, что это может быть решение, но я не вижу, как я могу это сделать. Программа должна быть очень отзывчивой, хотя, поскольку она является рекордером потока UDP, и если она блокируется слишком долго, это приведет к задержкам в файле.Как избежать цикла занятости в конкретном случае

Благодарю вас.

PS: Просто для информации, я все еще участвую, поэтому, пожалуйста, не обвиняйте меня, даже если решение может быть очевидным.


EDIT:

вот некоторые псевдо-код:

Когда запрос записи приходит, создать новое подключение и подключиться к адресу потока. Если это удастся, я построю свою fdset используя следующую функцию:

build_fdset() 
{ 
    int ii; 
    /* */ 
    FD_ZERO(&fdset); 
    /* */ 
    for (ii = 0; ii < max; ii++) 
    { 
     if (astRecorder[ii].bUsed != FALSE && astRecorder[ii].socket != INVALID_SOCKET) 
     { 
      FD_SET(astRecorder[ii].socket,&fdset); 
      /* */ 
      if (astRecorder[ii].socket > maxSocket) 
       maxSocket = astRecorder[ii].socket; 
     } 
    } 
} 

Затем цикл обработки соединений:

main_loop() 
{ 
    struct timeval timeout; 
    /* */ 
    timeout.tv_sec = 1; 
    timeout.tv_usec = 0; 
    /* */ 
    for (;;) 
    { 
     memcpy(&fdset_cpy,&fdset,sizeof(fdset)); 

     int ret = select((maxSocket + 1) , &fdset_cpy, NULL, NULL, &timeout); 

     if (iSelectRet <= 0) 
      continue; 
     else 
     { 
      int ii; 

      for(ii = 0; ii < max; ii++) 
      { 
       if ((recorders[ii].bUsed) && (FD_ISSET(recorders[ii].socket, &fdset_cpy))) 
       { 
        /* receive from socket */ 
        /* handle received data */ 
       } 
      } 
     } 
    } 
} 

ПРОБЛЕМА: Когда я установил таймаут timeout.tv_sec = 1 timeout.tv_usec = 0 все работает отлично, но я получаю 100% использование ЦП! Когда я даю NULL как тайм-аут, программа блокирует select(), хотя есть данные о сокетах.


РЕШЕНИЕ:

Ну, я наконец-то нашел ошибку! В приведенном выше коде я устанавливаю значения тайм-аута только один раз перед основным циклом. Проблема в том, что для fdset структура тайм-аута изменяется функцией select(). Таким образом, после выбора первого правильного тайм-аута структура тайм-аута изменяется функцией select() и устанавливается в 0. Это приводит к 0 таймауту, поэтому проблема заключается в том, что в следующий раз, когда цикл попадает в функцию выбора, к выбору 0 !!!

Большое спасибо тем, кто пытался помочь! Я его оцениваю =)

+0

Кроме того, что вы используете 'fd_setFlag' в' build_fdset' и 'fdset' в' main_loop', я не вижу ничего неправильного с вашим кодом. –

+0

Самое смешное, что в исходном коде есть функция fdset в обеих функциях. Я немного изменил код, чтобы опубликовать его здесь, и забыл переименовать fd_setFlag в верхней функции. Так что это не ошибка! – gekod

+0

Я просто не понимаю, почему он блокирует, если я установил тайм-аут в NULL – gekod

ответ

4

Тайм-аут вызова select может быть NULL, что означает подождать вечно.

+0

Так что вы на самом деле имеете в виду, что если я установил таймаут NULL, выбор будет блокироваться навсегда, пока не будут доступны данные? – gekod

+0

@gekod Да, это так. –

+0

Ну, я пробовал это, и я получаю, что при передаче тайм-аута NULL выбор никогда не продолжается, даже если есть данные в сокете. Если я устанавливаю тайм-аут в 1 секунду, все работает отлично (я могу читать из сокетов), но с исходной проблемой, что процессор перескакивает до 100% – gekod

0

Вы также можете использовать sleep после того, как вы проверите все свои потоки, чтобы отказаться от CPU в конце вашего цикла. Таким образом, вы не будете зависеть от одного потока от наличия входящих данных в ближайшем будущем, рискуя не обслуживать другие ваши потоки.

Смежные вопросы