LINUX.ORG.RU

управление потоком блокируемом в функции pselect


0

2

Всем привет, ситуация такая: я использую два потока: основной - в нём вся логика и дополнительный - в нём вся работа с сетью. Дополнительный поток большую часть времени блокирован в вызове pselect и я устанавливаю маску сигналов и когда мне нужно завершить работу приложения я отсылаю сигнал SIGINT дополнительному потоку и всё чики-пики. А теперь я хочу отсылать дополнительному потоку команды, скажем я создаю буфер и в него пишу что-то, пример команды:«соединиться с адресом ...». Ну мне нужно чтобы дополнительный поток сразу реагировал на это, и вот я подумал сделать так: я пишу в буфер и отсылаю сигнал SIGIO который перехватывается также как и SIGINT. Что думаете о таком подходе?


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

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

ну первая мысль была так и сделать :) но с сигналами кошерней :)

Onito
() автор топика

Либо сделай ещё один поток, с очередью заданий, либо в этом попеременно спи на кондиционной переменной/pselect'e.

Насчет сигналов, я точно не знаю, но этот чувак уверяет, что никто не гарантирует, в контексте какого потока выполниться обработчик сигнала, если ты с этим ок, то смотри сам тогда:)

___________________________

А, я не понял задумку:) Т.е. если послать процессу SIGIO, то он проснется на всех pselect'ах ?

batbko
()
Последнее исправление: batbko (всего исправлений: 2)
Ответ на: комментарий от batbko

да это ты прав, а внутри приложения можно писать в стандартный поток ввода? или както так :) ну тоесть я могу в select установить stdin и когда я ввожу данные в консоль то select сообщает о готовности этого дескриптора для чтения.

Onito
() автор топика
Ответ на: комментарий от batbko

ну у меня один pselect, мне нужно чтоб он просыпался по некоторому событию. И как ты правильно написал этот SIGIO( а тут можно использовать и SIGUSR) будет срабатывать в других потоках что мне не нужно. А нужно мне только один поток разбудить из select

Onito
() автор топика
Ответ на: комментарий от batbko

но этот чувак уверяет, что никто не гарантирует, в контексте какого потока выполниться обработчик сигнала

А если фигачить через pthread_kill, вместо простого kill, то POSIX гарантирует.

kim-roader ★★
()
Ответ на: комментарий от kim-roader

оО тоесть если я использую pthread_kill всё нормально? Сигнал будет отсылаться только потоку указанному в параметре? А то я тут сижу голову ломаю чё делать :)

Onito
() автор топика
Ответ на: комментарий от kim-roader

я не хочу пайпу делать, без неё красивее получается :)

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

тоесть если я использую pthread_kill всё нормально?

Игры с сигналами в многонитевом приложении часто кончаются плохо, особенно у нубов.

я не хочу пайпу делать, без неё красивее получается :)

С pipe и более красиво, и более надежно.

tailgunner ★★★★★
()
Ответ на: комментарий от Onito

Он там пишет не про то, что сигнал приходит всем потокам, а про то, что у нас отсутствует pthread_sigaction и у тебя нет возможности сделать так, чтобы у разных потоков были разные обработчики одного и того же сигнала.

А вообще man pthread_kill тебе английским по белому пишет:

Signal dispositions are process-wide: if a signal handler is installed, the handler will be invoked in the thread thread, but if the disposition of the signal is «stop», «continue», or «terminate», this action will affect the whole process.

kim-roader ★★
()
Последнее исправление: kim-roader (всего исправлений: 2)
Ответ на: комментарий от mky

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

Не сокеты, а пайпы.

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

Зачем ему пайпы? unix-сокеты дают дайтаграммы, то есть читающий поток просто получает команду целиком, ИМХО, так проще.

mky ★★★★★
()
Ответ на: комментарий от Onito

Создаётся сокет через socketpair(). Дополнительный поток каждый раз делая select() добавляет к ″fd_set *readfds″ дискриптор этого сокета. Как только основной поток туда что-то запишет, select() завершится и дополнительный поток «увидит», что есть данные в этом «управляющем» сокете. Для записи/чтения использовать sendmsg()/recvmsg(), что в отличии от пайпа, позволит передавать данные целиком. Поэтому, прочитав сообщение, дополнительный поток может просто по первому байту определить, что это за комада (0x01 — завершить работу, 0x02 — установить соединение), а в последующих байтах получить остальную информацию, допустим, ip-адрес, куда устанавливать соединение.

То есть не нужно создавать в общей памяти потоков какую-то область обмена, чтобы передать ip-адрес, и не нужно, в отличии от пайпа, заморачиватся с разделеним потока на отдельные команды. Головной поток может писать с MSG_DONTWAIT (O_NONBLOCK), чтобы не «уснуть» на записи, но при сокете, он либо запишет всё что хотел (и команду, и её данные), либо не запишет ничего.

А сигнальный механизм можно оставить для быстрого завершения работы...

mky ★★★★★
()

Если нужно не для фана, то просто заюзай libev.

bj
()

Лучше создать pipe и через тот же select обрабатывать команды с сокета.

Reset ★★★★★
()
Ответ на: комментарий от mky

Создаётся сокет через socketpair

AFAIK, socketpair непереносим.

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

Если тебе нужно больше PIPE_BUF байт «во полете», то ты что-то делаешь нее так.

tailgunner ★★★★★
()

epoll + eventfd

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

Он есть, если верить man'а в BSD, Linux, Solaris. Судя по тому, что ТС изначально писал про pselect() и SIGIO, он не собирается писать портируемый под винду код.

Я не про PIPE_BUF байт, а про то, что в общем случае, read/write не гарантирует, что прочитает/запишет именно сколько есть байт. Да и главный поток может отправить несколько команд подряд. Дополнительный поток, читая pipe, должен убедиться, что прочитал достаточно данных (и ОП-код и данные), при этом если прочиталось меньше байт, чем одна команда, или наоборот, прочиталось две команды, то держать эти данные до следующего чтения. Да, это простая, тривиальная задача, но зачем, решать её, если можно вместо использовать unix-сокет?

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

если прочиталось меньше байт, чем одна команда, или наоборот, прочиталось две команды, то держать эти данные до следующего чтения. Да, это простая, тривиальная задача, но зачем, решать её, если можно вместо использовать unix-сокет?

То есть ты предлагаешь использовать сокет, потому что его можно сделать datagram-oriented?

tailgunner ★★★★★
()
Ответ на: комментарий от mky

А sendmsg и recvmsg гарантирует что передадут столько сколько укажут? И при условии не блокируемого сокета?ну то есть я не хочу чтоб основной поток подвис по не важно каким причинам при передачи команд

Onito
() автор топика
Ответ на: комментарий от mky

А все прочитал до конца твое сообщение выше) а при каких условиях интересно в такой сокет запись может не произойти?

Onito
() автор топика
Ответ на: комментарий от tailgunner

Да. Но, если кому-то больше нравится использовать pipe, то пусть использует.

mky ★★★★★
()
Ответ на: комментарий от Onito

Есть ограничение на максимальный размер дейтаграммы в unix-сокете, в Linux'е это, 64 или 128 кбайт, в общем много. В других ОС может быть меньше, вот нагуглил, что в AIX это 4 кбайт, но всё равно, для одной команды приемлемо.

Ещё у ядра может не быть памяти под буфер сокета. Впрочем, как и под буфер любого другого сокета (udp, tcp). Это происходт, когда из сокета перестали читать данные, либо когда у ядра глобально не хватает памяти.

Что делать основному потоку, если дополнительный поток перестал читать из сокета или у ядра нет свободных буферов я не знаю. Наверно, подождать немного, попробовать записать ещё раз и завершать работу при неудаче. Но здесь нужно смотреть, можел ли у вас основной поток отправлять дополнительному очередную команду не дожидаясь выполнения предыдущей, то есть могут ли в сокете накапливаться команды, потому что установление tcp-соединения даже по ip-адресу может проходить достаточно долго, не говоря уж про резолвинг DNS-имени.

mky ★★★★★
()
Ответ на: комментарий от tailgunner

AFAIK, socketpair непереносим.

ха-ха! это да:)! и вот именно по этой причине можно увидить этот код:

[windows_utils.py: socketpair()]

(комментирую: разработчики Python — сделали прикольное решение заиспользовав socketpair. а на Винде они просто сделали кривенькую эмуляцию этого socketpair :))

user_id_68054 ★★★★★
()
Ответ на: комментарий от mky

Но здесь нужно смотреть, можел ли у вас основной поток отправлять дополнительному очередную команду не дожидаясь выполнения предыдущей, то есть могут ли в сокете накапливаться команды,

SO_SNDBUF можно покрутить.

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