Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / C++ [игнор отключен] [закрыт для гостей] / Можно прервать select() с таймаутом из другого потока? / 19 сообщений из 19, страница 1 из 1
12.04.2014, 14:03
    #38613107
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Есть цикл приема-отправки UDP-сообщений. Упрощенно так выглядит:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
while(true) {
	wait_time.tv_usec = 100000; // 0,1 сек
	int sel = select(sock + 1, &fd, NULL, NULL, &wait_time);
	if(sel == 0) { // 0,1 сек. прошло, принимать нечего, запуск внутренних заданий на отправку
		size_to_send = send_message(msg, addr, sleep_msec);
		if(size_to_send > 0) {// отправка
			sendto(sock, msg, size_to_send, 0, (SOCKADDR *) &addr, sizeof(sockaddr_in));
		}
	}
}



Для пассивного сервера подходит идеально: стоит на select() ждет входящие сообщения, тут же отвечает на них.

Для клиента проблема с отправкой. Проблема из-за таймаута select()
Делаю так: рабочий поток создает очередь сообщений для отправки, поток отправки в send_message() читает очередное сообщение и возвращает этому циклу, он отправляет. Но тут появляется лишняя пауза в из-за таймаута select(). Пока он не истечет - отправка не произойдет.

Вопрос: можно как-то из другого потока select() вывести из ожидания?

Есть варианты, которые мне не очень нравятся:
1. Запустить отправку из рабочего потока. (получится что сокет использую в двух потоках)
2. Послать из рабочего потока с другого сокета сообщение-команду на отправку, которая выведет select() из ожидания. (вообще изврат какой-то получится)
...
Рейтинг: 0 / 0
12.04.2014, 14:21
    #38613114
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima Tпоток отправки в send_message() читает очередное сообщение и возвращает этому циклу,
брр..
зачем поток отправки занимается чтением?
...
Рейтинг: 0 / 0
12.04.2014, 14:32
    #38613119
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
ИзопропилDima Tпоток отправки в send_message() читает очередное сообщение и возвращает этому циклу,
брр..
зачем поток отправки занимается чтением?
Читает из очереди на отправку (очередь заполняет другой поток). send_message() это моя callback-функция, которая готовит сообщение к отправке. Тут исходники если интересно.
Упростил пример, чтоб не грузить ненужными деталями.
...
Рейтинг: 0 / 0
12.04.2014, 14:43
    #38613124
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Получается такая картина
Время мсРабочий потокПоток отправки0select()10задание в очередь... ничего не происходит 90 мс 100select() выпал по таймауту101send_message() читает из очереди102sendto()
...
Рейтинг: 0 / 0
12.04.2014, 14:53
    #38613128
luislom
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima TЕсть цикл приема-отправки UDP-сообщений. Упрощенно так выглядит:


pselect умеет наносекунды. А вообще, можно использовать non-block сокеты,
прокручивать запуск чтение/записи порций данных в одном потоке, по дережированию
через select/pselect, и тяжёлый парсинг уже вынести в отдельный поток, связанный с реактором
очередью.
...
Рейтинг: 0 / 0
12.04.2014, 15:26
    #38613146
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
luislom pselect умеет наносекунды.
я и тут могу до 1 мкс таймаут опустить, вполне устроит, только зачем гонять пустой цикл? проц грузить?
Момент появления задания в очереди неизвестен. Например висим, ждем 5 часов, а потом пользователь нажал кнопку и надо как можно быстрее отправить.

Тут надо что-то фундаментально менять. Как вариант отправка из рабочего потока (вызов sendto()), только не вылезут глюки какие-нибудь из-за работы с одним сокетом в двух потоках? Я этот вопрос уже задавал однажды, мнения разделились.
...
Рейтинг: 0 / 0
12.04.2014, 16:08
    #38613169
luislom
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima TТут надо что-то фундаментально менять. Как вариант отправка из рабочего потока (вызов sendto()), только не вылезут глюки какие-нибудь из-за работы с одним сокетом в двух потоках? Я этот вопрос уже задавал однажды, мнения разделились.

Тогда Вам на Linux/epoll, или freebsd/kqueue. Не знаю вроде win IOCP из той же темы.
Например, при использовании epoll, зависаем на epoll_wait пока не появляется на одном сокете событие, после
чего пошли в цикл, если к моменту возвращения к epoll_wait на сокетах произошли события-получаем эти
сокеты и снова в цикл, если таковых нет-зависаем. Ещё есть boost::asio, очень интересная игрушка.
Там функиями async_read/async_write и передаваемыми в них асинхронными функциями-хендлерами, можно расписать
конечный автомат который будет читать/писать по мере поступления/отправки данных. Советую именно boost::asio,
он ещё и кроссплатформенный.
...
Рейтинг: 0 / 0
12.04.2014, 16:58
    #38613183
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
luislomзависаем на epoll_wait пока не появляется на одном сокете событие
select() тоже самое делает, только событие у меня НЕ на сокете появляется.

Почитал инет, пишут что sendto() thread-safe. Попробую слать из рабочего потока. На всякий случай оберну в критическую секцию чтобы одновременно оба потока не слали. К тому же мой send_message() совсем не thread-safe.
...
Рейтинг: 0 / 0
12.04.2014, 17:11
    #38613191
luislom
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima Tselect() тоже самое делает, только событие у меня НЕ на сокете появляется.


Нет, select гарантированно виснет на интервал времени,
epoll_wait возвращает управление немедленно, если на одном или нескольких сокетах или
пришли данные для чтения, или данные для отправки из буфера
были все отправлены в сеть (вспомним, что говорю про non block сокеты). В противном случае
спим, пока таковые события не произойдут.

Почитал инет, пишут что sendto() thread-safe. Попробую слать из рабочего потока. На всякий случай оберну в критическую секцию чтобы одновременно оба потока не слали. К тому же мой send_message() совсем не thread-safe.

У Вас имхо дизайн неуклюжий и неудачный. Пусть данные шлёт один поток, другие пусть занимаются обработкой.
Откройте для себя асинхронные, неблокирующие операции с сокетами. Сейчас это уже стандарт.
...
Рейтинг: 0 / 0
12.04.2014, 18:33
    #38613232
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
luislomselect гарантированно виснет на интервал времени,
это и хотел услышать, как один из вариантов ответов.

luislomОткройте для себя асинхронные, неблокирующие операции с сокетами. Сейчас это уже стандарт.
Операции у меня асинхронные, а сокеты синхронные. А открывать я буду пиво, т.к. надоела уже эта низкоуровневая трихомудия
...
Рейтинг: 0 / 0
12.04.2014, 19:00
    #38613236
luislom
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima T
А открывать я буду пиво, т.к. надоела уже эта низкоуровневая трихомудия

Это уютная верхушка. Если полезете в SOCK_RAW тогда пиво не прокатит-только грибы.
...
Рейтинг: 0 / 0
12.04.2014, 19:13
    #38613238
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
luislomЭто уютная верхушка. Если полезете в SOCK_RAW тогда пиво не прокатит-только грибы.
Туда точно не полезу, заглядывал. Если уж потребуется - найму профессионалов.
...
Рейтинг: 0 / 0
12.04.2014, 19:53
    #38613254
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima T,

есть простой трюк - создать сокет только для пробуждения,
http://stackoverflow.com/questions/384391/how-to-signal-select-to-return-immediately
...
Рейтинг: 0 / 0
13.04.2014, 08:16
    #38613392
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
ИзопропилDima T,

есть простой трюк - создать сокет только для пробуждения,
http://stackoverflow.com/questions/384391/how-to-signal-select-to-return-immediately
Почитал, как понял там добавляют в fd_set к TCP сокету второй сокет UDP и на него шлют что-нибудь через localhost. Он принимает и выводит select() из ожидания.
По сути это то что рассматривал вторым вариантом
Dima T2. Послать из рабочего потока с другого сокета сообщение-команду на отправку, которая выведет select() из ожидания. (вообще изврат какой-то получится)
Т.к. у меня изначально UDP, то второго сигнального не надо. Порт на localhost (куда слать) я знаю.
Склоняюсь к мнению что это наименьший изврат, т.к. по первому моему варианту (слать с двух потоков) надо прописывать синхронизацию потоков, и второй нехороший момент: остановить быстро поток отправки по команде я не могу, т.к. select() висит и надо ждать пока таймаут истечет.
...
Рейтинг: 0 / 0
13.04.2014, 12:43
    #38613473
Изопропил
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dima T,

обрати внимание, во вспомогательный сокет ничего не шлют, его просто закрывают
...
Рейтинг: 0 / 0
13.04.2014, 13:30
    #38613497
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Изопропилобрати внимание, во вспомогательный сокет ничего не шлют, его просто
закрывают
А что мешает закрыть основной?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
13.04.2014, 14:32
    #38613534
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
ИзопропилDima T,

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

В итоге так сделал
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
SOCKET sock_wakeup = SOCKET_ERROR; // глобальная переменная
...
while(true) {
	if(sock_wakeup == SOCKET_ERROR) {
		sock_wakeup = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	}
	fd_set fd;	
	FD_ZERO(&fd);
	FD_SET(sock_wakeup, &fd);
	FD_SET(sock, &fd);
	wait_time.tv_usec = 100000; // 0,1 сек
	int sel = select(sock + 1, &fd, NULL, NULL, &wait_time);
	if(sel == SOCKET_ERROR) {
		break;
	} else if(sel == 0 || FD_ISSET(sock_wakeup, &fd)) { 
		size_to_send = send_message(msg, addr, sleep_msec); // callback-функция подготовки сообщений
		if(size_to_send > 0) {// отправка
			sendto(sock, msg, size_to_send, 0, (SOCKADDR *) &addr, sizeof(sockaddr_in));
		}
		if(FD_ISSET(sock_wakeup, &fd)) {
			sock_wakeup = SOCKET_ERROR;
		}
	} else { // прием входящих
		int size = recvfrom(sock, ...);
	}
}



Другой поток вызывает для вывода select() из ожидания
Код: plaintext
1.
2.
3.
4.
5.
6.
void send_udp_now(bool close = false)
{
	if(sock_wakeup != SOCKET_ERROR) {
		closesocket(sock_wakeup);
	}
}



Тут опять вопрос с многопоточностью возникает: надо дополнительно синхронизацию потоков делать? sock_wakeup это общий ресурс получается, но пишет в него только один и closesocket() никаких исключений не вызывает на закрытом сокете.
...
Рейтинг: 0 / 0
13.04.2014, 14:35
    #38613535
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Dimitry SibiryakovА что мешает закрыть основной?

Если на этот момент будут входящие необработанные сообщения в буфере ОС, то можно будет про них забыть.
И bind() придется каждый раз делать.
...
Рейтинг: 0 / 0
14.04.2014, 18:34
    #38614628
Dima T
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Можно прервать select() с таймаутом из другого потока?
Не прошла моя конструкция реальные испытания. Получилось просто, красиво и ... неправильно ))

У select() разное поведение:
1. когда поток висит на select(), то при вызове closesocket(sock_wakeup) он возвращает 1 и FD_ISSET(sock_wakeup, &fd) = true (эту ситуацию мой код обрабатывает)
2. когда поток что-то делает, вызывается closesocket(sock_wakeup), затем доходит до select(), ему дается закрытый сокет, select() тут же возвращает SOCKET_ERROR (тут цикл прерывается). Причем FD_ISSET() для обоих сокетов дает true.

вот версия 2.0 если кому интересно (выделил изменения)
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
SOCKET sock_wakeup = SOCKET_ERROR; // глобальная переменная
...
wait_time.tv_usec = 0;
while(true) {
	fd_set fd;	
	FD_ZERO(&fd);
	if(sock_wakeup != SOCKET_ERROR) {
		FD_SET(sock_wakeup, &fd);
	}
	FD_SET(sock, &fd);
	int sel = select(sock + 1, &fd, NULL, NULL, &wait_time);
	wait_time.tv_usec = 0;
	if(sel == SOCKET_ERROR) {
		// прерываем цикл только по ошибке рабочего сокета
		if(sock_wakeup != SOCKET_ERROR) {
			closecocket(sock_wakeup);
			sock_wakeup = SOCKET_ERROR;
			continue;
		}
		break;
	} else if(sel == 0 || sock_wakeup == SOCKET_ERROR || FD_ISSET(sock_wakeup, &fd)) { 
		size_to_send = send_message(msg, addr, sleep_msec); // callback-функция подготовки сообщений
		if(size_to_send > 0) {// отправка
			sendto(sock, msg, size_to_send, 0, (SOCKADDR *) &addr, sizeof(sockaddr_in));
		} else if(sock_wakeup == SOCKET_ERROR || FD_ISSET(sock_wakeup, &fd)) {
			sock_wakeup = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		} else {
			wait_time.tv_usec = 100000; // 0,1 сек если делать нечего
		}
	} else { // прием входящих
		int size = recvfrom(sock, ...);
	}
}


Не очень красиво, на каждом входящем сообщении проверка || sock_wakeup == SOCKET_ERROR || FD_ISSET(sock_wakeup, &fd) , но похоже без этого никак.
...
Рейтинг: 0 / 0
Форумы / C++ [игнор отключен] [закрыт для гостей] / Можно прервать select() с таймаутом из другого потока? / 19 сообщений из 19, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]