Отменить поток с операцией чтения () на последовательном порту - PullRequest
3 голосов
/ 28 августа 2011

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

Как Apple предлагает в документах , я добавил флаг в словарь потоков, периодически проверяю, установлен ли флаг и, если да, вызываю [NSThread exit]. Это отлично работает.

Теперь поток может застрять в ожидании, когда последовательное устройство наконец отправит 12-байтовое сообщение. Вызов чтения выглядит так:

numBytes = read(fileDescriptor, buffer, 12);

Как только поток начинает читать с устройства, но данные не поступают, я могу установить флаг, чтобы сообщить потоку об окончании, но поток не будет читать флаг, пока он, наконец, не получит как минимум 12 байтов данных и продолжает обработку.

Есть ли способ уничтожить поток, который в данный момент выполняет операцию чтения на последовательном устройстве?

Изменить для уточнения: Я не настаиваю на создании отдельного потока для операций ввода-вывода с последовательным устройством. Если есть способ инкапсулировать операции, чтобы я мог их «убить», если пользователь нажал кнопку «Отмена», я был бы счастлив. Я разрабатываю приложение Cocoa для настольных компьютеров Mac OS X, поэтому никаких ограничений в отношении мобильных устройств и их возможностей не накладывается. Обходным решением будет немедленное возвращение функции чтения, если для чтения нет байтов. Как я могу это сделать?

Ответы [ 2 ]

2 голосов
/ 28 августа 2011

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

Установите тайм-аут, скажем, на полсекунды, и вызовитеэто в цикле при проверке, должен ли ваш поток завершиться.

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

1 голос
/ 28 августа 2011

Это именно то, для чего был разработан интерфейс pthread_cancel.Вы захотите обернуть блок с read в pthread_cleanup_push и pthread_cleanup_pop, чтобы вы могли безопасно очистить, если поток отменен, а также отключить отмену (с pthread_setcancelstate) в другом коде, который выполняется вэта тема, которую вы не хотите отменять.Это может быть проблемой, если правильная очистка будет включать несколько фреймов вызова;это по сути вынуждает вас использовать pthread_cleanup_push на каждом уровне вызова и структурировать ваш потокный код, такой как C ++ или Java, с обработкой исключений в стиле try / catch.

Альтернативным подходом будет установка обработчика сигналадля неиспользуемого в противном случае сигнала (например, SIGUSR1 или одного из сигналов реального времени) без флага SA_RESTART, чтобы он прерывал системные вызовы с помощью EINTR.Сам обработчик сигнала может быть полностью неактивным;единственная цель этого - прервать вещи.Затем вы можете использовать pthread_kill для прерывания read (или любого другого системного вызова) в определенном потоке.Преимущество этого в том, что вам не нужно переключать свой код на использование идиом типа C ++ / Java.Вы можете обработать ошибку EINTR, установив флажок (указывающий, был ли запрос запрошен на прерывание), и возобновить чтение, если флаг не установлен, или вернуть код ошибки, который приводит к очистке вызывающей стороны и в конечном итоге pthread_exit.

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

...