Как прервать фред-вызов? - PullRequest
6 голосов
/ 07 октября 2010

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

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

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

ОШИБКИ

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

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


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

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

Ответы [ 6 ]

9 голосов
/ 08 октября 2010

1.Сигналы:

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

2.Select ():

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

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

3.Выберите () и каналы:

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

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

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

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

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

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

4 голосов
/ 07 октября 2010

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

3 голосов
/ 07 октября 2010

Взгляните на man 2 kill. (Или см. здесь )

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

2 голосов
/ 07 октября 2010

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

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

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

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

0 голосов
/ 04 июня 2011

Обработчики сигналов не будут прерывать 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.

0 голосов
/ 07 октября 2010

Вы можете использовать системный вызов kill () .

UPDATE

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

...