Вопрос по c, linux, interrupt, fread – Как прервать фред-вызов?

6

У меня следующая ситуация:

Существует поток, который читает с устройства с вызовом Fread. Этот вызов блокируется, пока данные не отправляются с устройства. Когда я останавливаю эту тему, она остается внутри этой темы.

Теперь я обнаружил следующее на странице справки fread:

ОШИБКИ

Во всех системах, которые соответствуют спецификации Single UNIX, функция fread () устанавливает значение errno, как указано для следующих условий:

[EINTR] Операция чтения была прервана из-за получения сигнала, и данные не были переданы.

Это будет означать, что есть способ прервать вызов из другого потока. Но я понятия не имею, как. Может кто-нибудь сказать мне, как отправить сигнал, чтобы прервать вызов Fread? И какой сигнал мне нужно отправить?

Обновление 08-10-10 09:25

Я до сих пор не получил его на работу. Я пробовал kill () и pthread_kill () с разными сигналами. Но ничто, кажется, не прерывает вызов fread (). Единственное, что я получил, - это убить все приложение, но это не то, чего я хочу.

Интересно, что это связано с параллелизмом: я неправильно прочиталfread как кокни "нить". Jon Purdy

Ваш Ответ

6   ответов
0

убийство() Системный вызов.

ОБНОВИТЬ

Оказывается, я неправильно понял ваш вопрос. Как Р. указал ниже,kill() только для процессов убийства, а не потоков.

Это должен быть сигнал, для которого вы предварительно настроили обработчик сигнала (см.sigaction()) и имеютне использовалSA_RESTART флаг. mark4o
kill не будет работать. Тебе нужноpthread_kill который может отправить сигнал в конкретный поток. R..
Хорошая точка зрения; ответ обновлен ... Oliver Charlesworth
kill() Это нормально, если сигнал заблокирован в других потоках. mark4o
Можете ли вы сказать мне, какой сигнал мне нужно отправить с помощью системного вызова kill (), чтобы прервать fread ()? Peter Fortuin
9

1. Сигналы:

Использование сигналов, как отметили многие другие, будет работать. Однако, как отмечали многие другие, этот подход имеет свои недостатки.

2. Выберите ():

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

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

3. Выберите () и трубы:

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

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

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

4. Выберите (), трубы и сигналы:

Если вы используете несколько процессов и не хотите / не можете обойти канал, вы можете объединить оба решения. Создайте канал и установите обработчик сигнала, скажем, для SIGUSR1. В обработчике сигнала отправьте байт по каналу.

Всякий раз, когда процесс отправляет SIGUSR1, вызывается обработчик и разблокируется select (). Изучив fdsets, вы узнаете, что это произошло не по какой-либо другой причине, кроме как сигнализация самой вашей программы.

не было быselect() быть недостаточным, потому чтоfread() может сделать несколько звонковread()? Интересно, может быть, приведение потока в состояние ошибки в обработчике сигнала будет работать ... binki
2

freadблокировать сselect, когдаselect возвращает, проверьте переменную «Я сделал». Если не сделано, вы можете позвонитьfread чтобы получить данные.

В другом потоке, который хочет остановить поток фреда, вы можете установить переменную «Я готов» и затем закрыть fd, чтобы поток фреда проснулсяselect немедленно.

Если ваш контекст запрещает вам закрывать fd (вы упоминаете, что читаете с устройства, но говорите, что у вас есть сокет, который вы хотели оставить открытым), вы можете открыть второй fd, в который вы пишете, из другого потока, чтобы проснутьсяselect.

Как предлагается в комментариях ниже, закрытие fd, чтобы проснутьсяselect не может быть портативным Вы можете использовать вторую стратегию, упомянутую выше, чтобы добиться этого более мобильно.

@Ben: классно, но так ли это работает? Я просмотрел разделы select (2) и Threads спецификации SUS, но не заметил описания того, что ожидать, когда fd исчезнет из-под него, пока select () блокируется. OTOH Я полагаю, что-то разумное должно было случиться лучше, иначе есть потенциал для подвигов ... John Marshall
@Ben Voigt - Спасибо за указание на это. Отредактировал мой ответ соответственно. bstpierre
Или ты могclose() ФД перешел наselect() для того, чтобы немедленно отменить его, вместо использования логики опроса о потере заряда батареи при переключении контекста. Ben Voigt
@ Джон: кажется, чтоselect должен вернутьсяEBADF в таких условиях, но если вам это кажется непереносимым, bstpierre уже на правильном пути для другого подхода, который требует чуть больше работы: передайте второй файловый дескрипторselect где второй может быть записан (а не закрыт) для раннего пробуждения потока. Ben Voigt
fread может делать свою собственную буферизацию, такselect может ждать бесконечно, пока есть данные для чтенияfread Mark K Cowan
0

Обработчики сигналов не будут прерыватьсяfread если они не были установлены как прерывающие, а необработанные сигналы никогда не прерываются. Стандарт POSIX позволяет обработчикам, установленнымsignal по умолчанию используется функция прерывания или прерывания (а в Linux по умолчанию используется прерывание), поэтому, если вам нужно определенное поведение, используйтеsigaction функция и укажите желаемоеsa_flags, В частности, вам нужно опуститьSA_RESTART флаг. Например:

struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 };
sigaction(SIGUSR1, &sa, 0);

Обратите внимание, чтоsa_flags было бы неявно равно 0 в любом случае, если опущено, но я включил его явно в инициализаторе для иллюстрации. Тогда вы можете прерватьfread отправивSIGUSR1 сkill или жеpthread_kill.

3

man 2 kill, (Или посмотриВот)

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

@Ben Voigt: да, и я все еще думаю, что это уродливо каждый раз, когда я вижу это. ninjalj
@ninjalj: Не согласен с тобой, я предпочитаю использоватьpoll или AIO, которые имеют все преимуществаselect ни с какой неуклюжей логикой настройки аргумента. Но полезно знать такие шаблоны, как использованиеalarm установить время ожидания для блокирующего вызова ввода / вывода, чтобы вы могли распознать их при чтении существующего кода. Ben Voigt
В дополнение к генерации сигнала из другого потока сkill,alarm функция часто используется, чтобы вызвать блокировкуread призыв к тайм-ауту. Ben Voigt
Можете ли вы сказать мне, какой сигнал мне нужно отправить с помощью системного вызова kill (), чтобы прервать fread ()? Peter Fortuin
Вообще говоря, любой сигнал прерветfread() вызов. Тем не менее, вообще говоря, многие сигналы обычно также убивают ваше приложение (кроме SIGCONT). Я бы использовал SIGHUP или один из пользовательских сигналов лично. Но, как я уже сказал в своем ответе, я также вообще не люблю использовать сигналы для этой цели. (См. Ответ Джона Маршалла для альтернативы) Platinum Azure
4

select(2) системный вызов, который позволит вам определить, есть ли данные, доступные в этом файловом дескрипторе, без блокировки вообще или без блокировки только на этом устройстве.

fread буферизован, такselect может блокироваться на неопределенный срок, даже если есть данные, доступные для чтения Mark K Cowan
Хотя select () был бы полезен, на самом деле он не отвечает на вопрос. Michael Foukarakis
@ Майкл Фукаракис - Учитывая контекст, вопрос может быть задан длянеправильное решение большой проблемы, Джон дал разумный ответ, чтобы помочь ОП достичь своей цели, решив большую проблему. Downvote кажется немного резким. bstpierre
Я не могу судить о решении, не зная проблемы, не так ли? Может быть, ОПимеет использоватьfread(), Я не знаю, и я бы предпочел не предполагать. Michael Foukarakis

Похожие вопросы