реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Корректное завершение потока (pthread, Linux)
Kirill_Good
сообщение Jun 15 2013, 09:58
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Добрый день!

Не подскажите с реализациями завершения потоков? Как обработать такую ситуацию : дочерний поток висит на вызове блокируемой функции из third-party библиотеки. Родительский поток хочет его завершить. Как сделать? Учитывать корректное освобождение ресурсов.

Api: pthread, система: Linux

Спасибо!
Go to the top of the page
 
+Quote Post
alx2
сообщение Jun 18 2013, 03:47
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(Kirill_Good @ Jun 15 2013, 14:58) *
Не подскажите с реализациями завершения потоков?

Нет, я все-таки подскажу!!! sm.gif
Чтобы разбудить блокированный поток, пошлите ему сигнал SIGTHR: pthread_kill(thr, SIGTHR).

Ой, простите. SIGTHR есть только в BSD. Похоже, в linux Вам поможет только pthread_cancel().

Сообщение отредактировал alx2 - Jun 18 2013, 04:14


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
Kirill_Good
сообщение Jun 18 2013, 06:21
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Цитата(alx2 @ Jun 18 2013, 07:47) *
Нет, я все-таки подскажу!!! sm.gif
Чтобы разбудить блокированный поток, пошлите ему сигнал SIGTHR: pthread_kill(thr, SIGTHR).

Ой, простите. SIGTHR есть только в BSD. Похоже, в linux Вам поможет только pthread_cancel().


pthread_cancel() доходит до потока когда он натыкается на cancellation point и поток завершается после этой точки, можно добавить обработчики на выходе. Но если используется сторонняя библиотека и один из ее вызовов прервется на середине выполнения при cancel(), откуда знать что она не рухнет, когда в обработчике будет происходит освобождение ее ресурсов. Тоже самое с сигналом и его обработчиком. Или хорошая библиотека не должна так делать?)
В функциях может стоять if (errno == EINTR)

Сообщение отредактировал Kirill_Good - Jun 18 2013, 06:23
Go to the top of the page
 
+Quote Post
alx2
сообщение Jun 19 2013, 06:31
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091



Цитата(Kirill_Good @ Jun 18 2013, 11:21) *
Но если используется сторонняя библиотека и один из ее вызовов прервется на середине выполнения при cancel(), откуда знать что она не рухнет, когда в обработчике будет происходит освобождение ее ресурсов.

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

Если бы у Вас библиотека была в исходниках, я бы предложил использовать в ней poll/select. Но у Вас, как я понял, исходников нет. Не знаю, как в linux решить эту проблему.


--------------------
Всего наилучшего,
Alex Mogilnikov
Go to the top of the page
 
+Quote Post
alx.bilous
сообщение Jun 21 2013, 08:48
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 20
Регистрация: 18-03-12
Пользователь №: 70 865



Цитата
Не подскажите с реализациями завершения потоков? Как обработать такую ситуацию : дочерний поток висит на вызове блокируемой функции из third-party библиотеки. Родительский поток хочет его завершить. Как сделать? Учитывать корректное освобождение ресурсов.


Вы можете просто убить поток, а освободить ресурсы в том месте где убили, но для этого надо иметь явный контекст потока
Go to the top of the page
 
+Quote Post
Kirill_Good
сообщение Jun 21 2013, 08:57
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Цитата(alx.bilous @ Jun 21 2013, 12:48) *
Вы можете просто убить поток, а освободить ресурсы в том месте где убили, но для этого надо иметь явный контекст потока

а не будет ли это одно и тоже, что и освободить ресурсы в обработчиках при завершении? Явный контекст потока , вы имели ввиду, что ясно представлять код?

Вроде как напрашивается только одно решение: делать код потока неблокируемым.
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Jun 22 2013, 19:05
Сообщение #7


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(Kirill_Good @ Jun 21 2013, 12:57) *
...Вроде как напрашивается только одно решение: делать код потока неблокируемым.


будет всё левак. самое грамотное - в сторонней библиотеке должна быть функция старта-останова стороннего потока. всё остальное - хождение по тонкому льду. шаг влево или вправо (не обязательно вы и не обязательно в ближайшем будущем) и кирдык всей конструкции.
Go to the top of the page
 
+Quote Post
Kirill_Good
сообщение Jun 23 2013, 05:39
Сообщение #8


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Цитата(kolobok0 @ Jun 22 2013, 23:05) *
в сторонней библиотеке должна быть функция старта-останова стороннего потока.


а есть пример какой-нибудь?
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Jun 25 2013, 13:14
Сообщение #9


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(Kirill_Good @ Jun 23 2013, 09:39) *
.. пример..


пример чего? вызов функции или параметров возвращаемых? Или потроха самой функции?

сами функции чего-то аля (без привязки к юниксу или языку).

Код
HANDLE Start();

error Stop(HANDLE);


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

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

Go to the top of the page
 
+Quote Post
Kirill_Good
сообщение Jun 25 2013, 13:31
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Цитата(kolobok0 @ Jun 25 2013, 17:14) *
пример чего? вызов функции или параметров возвращаемых? Или потроха самой функции?

сами функции чего-то аля (без привязки к юниксу или языку).

Код
HANDLE Start();

error Stop(HANDLE);


Вы наверно невнимательно прочитали тему. Вы дали "пример" функций о реализации которых тема и заводилась. Как вы сами описали, что эти функции часть api библиотеки. Где же место пользовательскому коду здесь?) Согласен с ситауцией допустим воспроизведение видео файла lib::start("file_path"); lib::stop(); Но такой простой api почти всегда не прокатывает. Такие функции носят больше reference характер, чем использование в рабочем коде. Также не все библиотеки имеют такой реферс. Всегда приходится реализовывать их самому. Вот об этом и вопрос. О конктретной части правда, как в функции stop() реализовать корректый останов потока?
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Jul 8 2013, 10:44
Сообщение #11


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(Kirill_Good @ Jun 25 2013, 17:31) *
... Где же место пользовательскому коду здесь?)...


Вы не вчитывались в мой первый ответ.

"будет всё левак. самое грамотное - в сторонней библиотеке должна быть функция старта-останова стороннего потока. всё остальное - хождение по тонкому льду. шаг влево или вправо (не обязательно вы и не обязательно в ближайшем будущем) и кирдык всей конструкции."

т.е. делать останов _не_ своей ветки = есть зло. Так понятней? Вы не можете гарантировать, не зная внутреннего устройства ветки, что она тормознётся _корректно_ !!! Т.е. если вы затачиваетесь на внутреннюю логику поведения библиотеки при том или ином Вашем внешнем воздействии - то это чревато в будущем(как минимум). Т.е. при незначительном изменении кода самой библиотеки, Вы рискуете опять начать всё сначала (разведку, перепрограммирования своего кода вызова-останова, тестирование).


если идёт речь о не понимании как это сделать _внутри_ библиотеки - то это попытка второго моего ответа. Т.е. внутри библиотеки, должно быть обеспечено на фазе старта:
1) вход
2) захват общих ресурсов, если есть. подготовка к старту нитки.
3) подъём нитки.
4) ожидание до окончания синхронной фазы подъёма (!!! эту фазу многие пропускают. чревато проблемами при ударных нагрузках на систему в целом).
5) обработка ошибок
6) выход.

При этом внутри подымаемой нитки код будет приблизительно следующий
1) вход
2) захват локальных (ведомых данной ниткой) ресурсов
3) обработка ошибок
4) сигнализация паренту о готовности к работе, либо ошибке.
5) уход на ожидание события либо саму работу.
---
6) бла-бла-бла (работа типа)
----
7) ожидание начала останова нитки из вне.
8) освобождение своих локально захваченных ресурсов.
9) обработка ошибок
10) сигнализация об успешном окончании нитки, либо ошибке
11) выход.

с 1 по 5 пункты зеркальны к пунктам с 7 по 11. Т.е. если Вы в нитке частично завхатили ресурсы, то и на выходе Вы должны освободить только захваченные ресурсы.

код останова будет выглядеть приблизительно следующим.
1) вход
2) выставили сигнальчик нитке об останове.
3) ожидание останова нитки.
4) освобождение общих ресурсов, если есть
5) обработка ошибок
6) выход


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

Сообщение отредактировал kolobok0 - Jul 8 2013, 10:46
Go to the top of the page
 
+Quote Post
Kirill_Good
сообщение Jul 8 2013, 11:05
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Давайте я расскажу ход моих мыслей, когда я читал ваши ответы.

Цитата(kolobok0 @ Jul 8 2013, 14:44) *
...Вроде как напрашивается только одно решение: делать код потока неблокируемым.

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


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

Цитата(kolobok0 @ Jul 8 2013, 14:44) *
т.е. делать останов _не_ своей ветки = есть зло. Вы не можете гарантировать, не зная внутреннего устройства ветки, что она тормознётся _корректно_ !!! Т.е. если вы затачиваетесь на внутреннюю логику поведения библиотеки при том или ином Вашем внешнем воздействии - то это чревато в будущем(как минимум). Т.е. при незначительном изменении кода самой библиотеки, Вы рискуете опять начать всё сначала (разведку, перепрограммирования своего кода вызова-останова, тестирование).

С этим я соглашусь. Эту мысль я отразил в своей фразе ...Вроде как напрашивается только одно решение

Затем.

Цитата(kolobok0 @ Jul 8 2013, 14:44) *
Для обеспечения постоянного мониторинга связи парент-чайлд применяют не блокирующие функции ввода-вывода. Обычно у чайлда всю работу делают квантованной и обрабатывают порциями. При этом обычно выделяется основной цикл, внутри которого обрабатывают в том числе и сигналы приходящие от парента.


То есть вы предложили вариант, который отвергли в предыдущем сообщении.

Так же я писал.

Вот об этом и вопрос. О конктретной части правда, как в функции stop() реализовать корректый останов потока?

Вы написали кусок текста про работу с потоками, который не содержал ответа на вопрос.

Тут либо я тугой, либо кто то другой. Если я, то признаю , если будут аргументы.
Go to the top of the page
 
+Quote Post
firew0rker
сообщение Jul 8 2013, 11:08
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 206
Регистрация: 11-07-12
Из: Новосибирск
Пользователь №: 72 716



В дочернем потоке вызвать
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
перед вызовом блокируемой функции.
Тогда дочерний поток может быть завершен с помощью pthread_cancel в любой момент, в т.ч. когда висит на вызове блокируемой функции.
Go to the top of the page
 
+Quote Post
Kirill_Good
сообщение Jul 8 2013, 11:11
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 217
Регистрация: 10-12-10
Из: Москва
Пользователь №: 61 528



Цитата(firew0rker @ Jul 8 2013, 15:08) *
В дочернем потоке вызвать
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
перед вызовом блокируемой функции.
Тогда дочерний поток может быть завершен с помощью pthread_cancel в любой момент, в т.ч. когда висит на вызове блокируемой функции.


а где освобождить ресуры?
Go to the top of the page
 
+Quote Post
firew0rker
сообщение Jul 8 2013, 12:17
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 206
Регистрация: 11-07-12
Из: Новосибирск
Пользователь №: 72 716



Цитата(Kirill_Good @ Jul 8 2013, 17:11) *
а где освобождить ресуры?

Зависит от конкретной реализации. Наверное, там же, где вызывается pthread_cancel.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 12:48
Рейтинг@Mail.ru


Страница сгенерированна за 0.01489 секунд с 7
ELECTRONIX ©2004-2016