LINUX.ORG.RU

Асинхронный ввод/вывод и pthreads.


0

0

Как известно, асинхронный ввод/вывод происходит по сигналу SIGIO.
Но вот незадача, если у нас на каждый поток приходится по соединению(сокету), то как определить в какому потоку(сокету) пришел этот сигнал????

select или poll не предлагать, надо именно по сигналу реакцию.

Зачем это надо?
Вот типичный случай:

int stop = 0;
......

void sig_io(int sig)
{
recv(sock, stop, sizeof(stop));
}

.....

while(1)
{
send(sock, ...);
if(stop)
break;
}

Т.е. нужно уметь получить команду на остановку в любой момент времени.

Причем нужно эту функциональность перенести на несколько потоков, чтобы каждый поток смог так работать.

anonymous

Сигналы плохо уживатся с тредами. А уж SIGIO - в особенности.

> select или poll не предлагать, надо именно по сигналу реакцию.
А почему? Приведенный пример просто вопиет быть реализованным на select'e.

Die-Hard ★★★★★
()

если в цикл вставить select с recv, то получится тормозно, поскольку будет блокировка на время timeout в select, а recv редко принимается.

Вот что в мане вычитал(man 2 fcntl):

Используя F_SETSIG вместе с ненулевым значением и задавая обработчику сигнала флаг SA_SIGINFO (см. sigaction(2)), можно передать этому обработчику дополнительную информацию о событиях ввода-вывода с помощью структуры siginfo_t. Если поле si_code задает, что источником является SI_SIGIO, то поле si_fd содержит файловый дескриптор, на котором произошло событие.

Выбрав сигнал реального времени, соответствующий стандарту POSIX (значение >= SIGRTMIN), можно использовать очереди из множества событий ввода-вывода, использующих один и тот же номер сигнала. (Построение очереди зависит от доступной памяти). Дополнительная информация доступна, если для обработчика установлен SA_SIGINFO, как описано выше.

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

Есть ли альтернатива? Данный способ будет работать только в linux(F_GETSIG и F_SETSIG специфичны для Linux. ), а в BSD тоже хочется.

anonymous
()

Делай select сразу на чтение и на запись в твой сокет,
например

select(sock,  &read_set, &write_set, &except_set, ZERO_TIMEOUT);
if(FD_ISSET(sock, read_set))
{
  read(sock, ...);
}

if(FD_ISSET(sock, write_set))
{
 write(sock, ...);
}

if(FD_ISSET(sock, except_set))
{
 ??
}

anonymous
()

Вот это будет истиной всегда(буффер всегда доступен):

if(FD_ISSET(sock, write_set)) { }

anonymous
()
Ответ на: комментарий от anonymous


> ...получится тормозно, поскольку будет блокировка ...
Извини, я не понимаю, чего тебе надо.

В описанном тобой примере управление во всех тредах напрочь блокировано
до наступления IO события, причем каждый тред жрет максимум CPU. Чтобы такого
не было, придумали select().


Die-Hard ★★★★★
()

это всего лишь пример, причем блокировка происходит на время выполнения send();

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

а в select и poll событие write всегда истина, проверял.

anonymous
()

Проблема решилась с помощью poll(больше нравится). Проверил еще раз, действительно событие POLLIN не затирается POLLOUT! Все дело в порядке проверки дескриптора, так сработало:

if( fds[0].revents & POLLIN ) { .... recv ....... } else if( fds[0].revents & POLLOUT ) { .... send ....... }

есть еще вариант с POLLPRI - есть срочные данные

В общем poll() решил все проблемы.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.