Как закрыть поток c

от admin

Прерывание потока

Иногда поток полезно прервать до его нормального завершения. Например, отладчику может понадобиться прервать вышедший из-под контроля поток. После прерывания поток удаляется из системы и не может быть начат снова. Для прерывания потока до его нормального завершения служит метод Abort(). Ниже приведена простейшая форма этого метода:

Метод Abort() создает необходимые условия для генерирования исключения ThreadAbortException в том потоке, для которого он был вызван. Это исключение приводит к прерыванию потока и может быть перехвачено и в коде-программы, но в этом случае оно автоматически генерируется еще раз, чтобы остановить поток. Метод Abort() не всегда способен остановить поток немедленно, поэтому если поток требуется остановить перед тем, как продолжить выполнение программы, то после метода Abort() следует сразу же вызвать метод Join().

Кроме того, в самых редких случаях методу Abort() вообще не удается остановить поток. Это происходит, например, в том случае, если кодовый блок finally входит в бесконечный цикл. В приведенном ниже примере программы демонстрируется применение метода Abort() для прерывания потока:

Метод Abort()

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

В некоторых случаях оказывается полезной другая форма метода Abort (), приведенная ниже в общем виде:

где stateInfo обозначает любую информацию, которую требуется передать потоку, когда он останавливается. Эта информация доступна посредством свойства ExceptionState из класса исключения ThreadAbortException. Подобным образом потоку можно передать код завершения.

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

Вызов метода ResetAbort() может завершиться неудачно, если в потоке отсутствует надлежащий режим надежной отмены преждевременного прерывания потока. Давайте модифицируем вышеуказанный пример:

Ввод-вывод и работа с файлами

Файл в языке Си рассматривается как неструктурированная последовательность байтов. С этой точки зрения в языке программирования C файлом может быть как собственно файл на жестком диске, так и принтер, дисплей и другие подключаемые устройства ввода-вывода.

Как правило, взаимодействие между приложением и файлами производится посредством обмена блоков байт фиксированной длины (обычно длина представляет степень двойки — 256 или 512 байт).

При чтении из файла данные помещаются в буфер операционной системы, а затем побайтно передаются приложению.

При записи в файл данные накапливаются в буфере, а при заполнении буфера записываются на диск в виде единого блока байт.

Буферы представляют участки памяти, поэтому передача данных между приложением и буфером происходит довольно быстро в отличие от взаимодействия с физическими устройствами типа принтера.

Файл вместе с предоставляемыми средствами буферизации представляет поток .

Язык программирования Си содержит необходимый функционал для работы с файлами и устройствами ввода-вывода. Для применения его применения в программе необходимо подключить заголовочный файл stdio.h .

Открытие и закрытие потоков

Чтобы работать с потоком, его необходимо открыть. Для открытия потока применяется функция fopen() , которая имеет следующий прототип:

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

Функция возвращает указатель на структуру, которая имеет тип FILE , определенный в том же файле stdio.h. Этот указатель идентифицирует поток в программе и через него мы сможем обращаться к открытому файлу.

При открытии поток связывается со структурой

Режимы открытия

Каждый режим задается в виде набора символов. В частности, мы можем использовать следующие режимы:

«w» : текстовый файл открывается для записи. Если файл ранее существовал, то он пересоздается и записывается заново

«r» : текстовый файл открывается для чтения

«a» : текстовый файл открывается для добавления в него новых данных. Если файл существовал ранее, то данные просто добавляются

«w+» : текстовый файл создается для записи/записи. Если файл ранее существовал, то при первой записи после открытия он пересоздается и записывается заново. А при последующих записях после открытия данные добавляются в него без перезаписи.

«r+» : текстовый файл открывается для чтения/записи. Запись допустима в любом месте файла, кроме конца файла, то есть недопустимо увеличение размеров файла.

«a+» : текстовый файл открывается или создается (при его отсутствии) для чтения/записи. В отличие от режима w+ файл при открытии не пересоздается заново, а в отличии от режима r+ можно записывать данные в конец файла

Читать:
Как удалить все скрытые листы в excel

«wb» : бинарный файл открывается для записи

«rb» : бинарный файл открывается для чтения

«ab» : бинарный файл открывается для дозаписи

«w+b» : бинарный файл создается для записи/чтения

«r+b» : бинарный файл открывается для чтения/записи

«a+b» : бинарный файл открывается или создается (при его отсутствии) для чтения/дозаписи

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

Закрытие файла

После завершения работы с файлом его следует закрыть. Для этого применяется функция fclose() :

Единственный параметр функции представляет ранее полученный при открытии файла указатель на структуру FILE, связанный с файлом.

Функция возвращает число: 0 — в случае успешного выполнения и встроенное значение EOF в случае ошибки.

Например, откроем и закроем файл «data.txt», который расположен в одной и той же папке, что и выполняемая программа:

Если файл расположен в каком-то другом месте, то можно указать соответствующий относительный или абсолютный путь. Например, «С:\\data.txt» (если файл data.txt расположен в корне диска C).

Обработка ошибок

В процессе открытия или создания файла мы можем столкнуться с рядом ошибок, например, при открытии в режиме чтения не окажется подобного файла, недостаточно памяти и т.д. И в случае возникновения ошибки функция fopen() возвращает значение NULL . Мы можем обработать возникновение ошибки с помощью проверки результата функции:

Для вывода ошибки на консоль применяется встроенная функция perror() . И так как дальнейшие действия в программе в случае ошибки при открытии файла смысла не имеют, то с помощью вызова return 1; завершаем работу приложения и возвращаем число, отличное от нуля (обычно ненулевое число рассматривается как код ошибки).

И если при попытке открытия файла по указанному пути его не окажется, то консоль выведет следующую ошибку:

Закрытие потока и освобождение объектов внутри его

Вызывается остановка сервера и идет закрытие фоновых потоков, но фоновые потоки получают состояние WaitSleepJoin, так как имеют внутри объект. Чтобы закрыть поток, требуется уничтожить все объекты в нем, но я не знаю как правильно это сделать, так как поток является ParameterizedThread.

Как правильно закрыть остановить сервер, чтоб все дочерние потоки уничтожились вместе с помещенными объектами?

i4el0vek's user avatar

Объекты не имеют к потокам никакого отношения. Чтобы закрыть поток, надо просто вернуть управление ( return , а не Thread.CurrentThread.Abort(); ) из метода потока. Это единственное условие закрытия. Не надо делать Abort самому себе 🙂

Делать Abort другим потокам не рекомендуется. Стоит использовать объекты синхронизации и/или просто глобальные свойства-флаги остановки, по которым функции потоков сами будут возвращать управление.

WaitSleepJoin означает, что поток ждет чего-то. Посмотрите в отладчике его stack trace и узнайте, чего именно. В коде из вопроса поток скорее всего ждет получения данных из сети. Красиво прервать синхронное ожидание не получится. Стоит или задать достаточно небольшой ReadTimeout , или использовать асинхронные методы чтения, которые позволяют прерывать ожидание в любой момент.

Как правильно прервать поток в Си?

20-50 запросов к API ВКонтакте,
при том хотелось бы оставить себе право посылать команды из консоли, в том числе quit .
Реализацию накатил простую — вывел запросы в новый поток, который крутится пока
не изменится флаг. Однако в таком случае я таки использую глобальную переменную.
Сделал все примерно так:

Хотелось бы услышать мнение опытных разработчиков в данном вопросе. Может стоит вынести флаг в параметры потока, или есть какая-то конкретная функция для данных целей?

  • Вопрос задан более трёх лет назад
  • 404 просмотра
  • Facebook
  • Вконтакте
  • Twitter

Общее правило при работе с потоками, не специфичное для С или pthreads: состояние резделяемое между потоками должно быть или атомарным или должно быть защищено примитивом синхронизации.
Код функции thread_process никак не гарантирует, что компилятор не выкинет проверку !quit , потому что quit не меняется в этой функции и в функциях вызываемых из неё.

Учитывая, что атомарность и потоки вошли в стандарт С11 имеет смысл смотреть туда.
Если С11 недоступен, смотреть в pthread_mutex_*, pthread_cond_*, .

По-хорошему — да, стоит. Это, однако, ортогонально к синхронизации доступа.

Вместо busy wait лучше использовать sleep или что-нибудь типа pthread_mutex_timedlock / pthread_cond_timedwait .

Похожие статьи