Russian Qt Forum

Qt => Общие вопросы => Тема начата: OKTA от Апрель 11, 2014, 17:14



Название: Библиотека-убийца
Отправлено: OKTA от Апрель 11, 2014, 17:14
Товарищи, подскажите, как лучше поступить в следующей ситуации.
Подключаю через QLibrary библиотеку. Нахожу в ней адрес нужной мне функции, через которую все операции с этой библиотекой происходят и начинаю с ней работать. Структура библиотеки едина, но самих таких библиотек может быть несколько.
И иногда встречаются случаи, когда чьи-то кривые руки сделали эту библиотеку не по стандарту.. Вызываю функцию библиотеки, а она, собака, стопорит поток, не возвращая значение. Я знаю, что этого быть не должно и в этом случае надо прервать все работы с этой библиотекой. Каким образом лучше всего это сделать?


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 11, 2014, 17:16
Параллельно с вызовом функции библиотеки запустить таймер (возможно в другом потоке), и если по истечении времени таймера выхода их функции нет, то сообщать об этом.


Название: Re: Библиотека-убийца
Отправлено: OKTA от Апрель 11, 2014, 17:22
Таймер да, о нем я тоже подумал. Но он только даст сигнал, что "что-то не так с библиотекой". Вопрос в том, как можно ее безопасно выгрузить? Простой unload убьет всю программу целиком, т.к. к моменту, когда происходит это зависание, уже много чего инициализировано в памяти самой этой библиотекой (и к этим данным не достучаться) :-\


Название: Re: Библиотека-убийца
Отправлено: kamre от Апрель 11, 2014, 19:13
в этом случае надо прервать все работы с этой библиотекой. Каким образом лучше всего это сделать?
В отдельном процессе запускать функции библиотеки, а если что, то прибивать процесс.


Название: Re: Библиотека-убийца
Отправлено: OKTA от Апрель 11, 2014, 20:34
Это уже не просто функции библиотеки запускать в отдельном процессе, а приложение отдельное делать, которое будет работать с библиотеками  :-\ а это жесть, учитывая специфику этих библиотек.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 11, 2014, 21:54
Почему приложение? Говорите уж тогда специфику, тогда мб что придумаем :)


Название: Re: Библиотека-убийца
Отправлено: Alex Custov от Апрель 11, 2014, 21:59
Почему приложение? Говорите уж тогда специфику, тогда мб что придумаем :)

Просто интересно - а как функцию из библиотеки можно запустить в отдельном процессе без написания ещё одной программы-обёртки?


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 12, 2014, 13:47
псевдокод.
Код:
::CreateThread(blabla, названиефункции).


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 12, 2014, 15:02
псевдокод.
Код:
::CreateThread(blabla, названиефункции).
Это запуск в отдельной нитке, того же процесса.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 12, 2014, 15:20
Виноват, невнимательно прочитал.

Довольно сложно, но можно. Идём в чужой процесс, залазим к нему в память, разворачиваем там свой лагерь и что угодно делаем. Но это для проблемы уже слишком масштабно. Ммм... да, видел где то инициацию форка эксплорера, правда для других задач, но в качестве расходного процесса пойдёт :)

А если своя обертка, просто локальные сокеты и запуск отдельного процесса со связью.

PS у меня есть опыт в этой области, но она "на грани" разумного :D


Название: Re: Библиотека-убийца
Отправлено: xokc от Апрель 13, 2014, 08:42
Это уже не просто функции библиотеки запускать в отдельном процессе, а приложение отдельное делать, которое будет работать с библиотеками  :-\ а это жесть, учитывая специфику этих библиотек.
К сожалению ничего умнее, чем делать отдельное приложение, которое будет грузить эти библиотеки и взаимодействовать через IPC с главным приложением выдумать не получится - не зря в Хроме для того, чтобы обесчестить независимость (в смысле стабильности) от плагинов каждая вкладка как отдельный процесс реализована.


Название: Re: Библиотека-убийца
Отправлено: Igors от Апрель 13, 2014, 09:37
Я знаю, что этого быть не должно и в этом случае надо прервать все работы с этой библиотекой. Каким образом лучше всего это сделать?
"вынести в процесс" - удовольствие дорогое. Интересно попробовать механизм передачи исключений между нитками. В Qt 5 что-то есть (не вникал)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 10:18
"вынести в процесс" - удовольствие дорогое.
Да.
Но процесс мы можем убить без последствия для других процессов, а вот нитку для процесса не всегда.

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


Название: Re: Библиотека-убийца
Отправлено: Igors от Апрель 13, 2014, 11:14
А какой в этом смысл? Если бы функция из библиотеки могла сама определять, что она зависла, то ей не обязательно было бросать исключение, достаточно просто завершаться.
Смысл "прерваться" и вернуть управление вызывающему. Очень может быть что такое прерывание окажется некорректным или вообще не сработает, но это хотя бы позволит толкать либу в главной нитке без затей - уже легче


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 11:22
Смысл "прерваться" и вернуть управление вызывающему. Очень может быть что такое прерывание окажется некорректным или вообще не сработает, но это хотя бы позволит толкать либу в главной нитке без затей - уже легче

Вот функция.
Она будет немного долго выполняться, запустите ее пожалуйста как хотите, что бы она через пять секунд вышла. Хотите с исключениями, хотите без.
Код
C++ (Qt)
void func()
{
   for(;;)
   {
   }
}
 



Название: Re: Библиотека-убийца
Отправлено: Igors от Апрель 13, 2014, 11:44
Вот функция.
Она будет немного долго выполняться, запустите ее пожалуйста как хотите, что бы она через пять секунд вышла. Хотите с исключениями, хотите без.
В том-то и дело что выйдет если удастся передать в эту нитку исключение. Как это сделать - не знаю. Вроде в WinAPI такая возможность есть, но это не моя основная платформа. А в букваре Qt 5 пишут что передавать можно - вот это интересно было бы проверить.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 12:03
Сами напросились. Вот примерчик https://dl.dropboxusercontent.com/u/101053289/Program/testFuncThreadStopForced.zip.

Щелчок - запуск ф-ции/остановка ф-ции.

Потоки внутри выглядят вот так
Код:
	void run()
{
for(long i = 0; ; i++)
{
// не даёт заспамить сигналами всё вокруг
if (i == 100000000)
{
state_ = !state_;
emit state(state_);
i = 0;
}

}
}
Вроде все условия выполнены. Остановка неизвестной ф-ции через неопределённое количество времени :)

Потоков всего 5, ибо пустые и грузят проц под 99 :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:23
Вроде в WinAPI такая возможность есть, но это не моя основная платформа.
Бросить C++ исключение через WinAPI? Вряд ли. :)
Если имеется ввиду SEH, то это не исключения C++.

А в букваре Qt 5 пишут что передавать можно - вот это интересно было бы проверить.
Передать можно из одного потока в другой, так же как и сигналы. Но, повторюсь, функция никакие исключения не шлет.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:25
Сами напросились.
А что это? :)


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 14:26
Это функция в потоке, которую ты же и просил :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:38
Это функция в потоке, которую ты же и просил :)
Есть функция func, она спрятана в библиотеке. Ее нужно прервать через 5 секунд.
А это я не знаю что. :)


Название: Re: Библиотека-убийца
Отправлено: Igors от Апрель 13, 2014, 14:39
Передать можно из одного потока в другой, так же как и сигналы. Но, повторюсь, функция никакие исключения не шлет.
Не она шлет, а ей пошлют (а она (ее  вызывающий) поймает). Вот это было бы хорошее дело. Но может все это мои фантазии - не проверял.

Это функция в потоке, которую ты же и просил :)
??? Не врубился, о чем Вы?


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:40
Не она шлет, а ей пошлют (а она (ее  вызывающий) поймает). Вот это было бы хорошее дело. Но может все это мои фантазии - не проверял.
Нечем ей (от ее имени) послать исключение C++. :)


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 14:45
Кхм.

Ладно, видимо выходной на вас влияет :D

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

То, что я её сразу запихал в поток, а не извлекал из dll - для простоты. В 100 из 100 случаев нормальная отработка.

Ещё проще - у нас есть бесконечная функция в потоке. Мы можем её грохнуть в любой момент времени.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:47
То, что я её сразу запихал в поток, а не извлекал из dll для простоты. В 100 из 100 случаев нормальная отработка.
Запихайте пожалуйста, что бы я увидел, в каком месте она вызывается.
Вот прямо что бы так было написано. :)
func();


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 14:51
А хохо не хуху? :D

Прямое написание будет равнозначно вызову функции.

Для прекращение работы зависшей функции нужна обертка.

Т.е. неизбежно будет saveFunction(&func, 6) допустим.
Если процедура унифицированная, то вполне возможно и просто создавать потоки на каждое выполнение функции.

PS собственно у вас и проблема, что сама функция не имеет этого механизма. В общем глупое заявление :D

PPS модифицируем пример и вуаля - у вас в обертке вызывается функция с защитой от зависания.
Код:
	void run()
{
          func();
}


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:54
Прямое написание будет равнозначно вызову функции.
Ну так нам ее и надо...

Для прекращение работы зависшей функции нужна обертка.
Прекрасно. Какая? Хочу посмотреть код. :)

Т.е. неизбежно будет saveFunction(&func, 6) допустим.
Хорошо, вот что там в saveFunction мы и ждем... :)

Если процедура унифицированная, то вполне возможно и просто создавать потоки на каждое выполнение функции.
Так вроде и пытаемся создавать. Только толку ноль. :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 14:55
PPS модифицируем пример и вуаля - у вас в обертке вызывается функция с защитой от зависания.
Прекрасно, где же это чудо обертка? :)


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 14:56
Представьте в моем предыдущем сообщении прикреплена ссылка на архив с исходниками, Оо. Или вы её так небрежно не заметили? :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:01
Представьте в моем предыдущем сообщении прикреплена ссылка на архив с исходниками, Оо. Или вы её так небрежно не заметили? :)
Скажите пожалуйста в каком месте вызывается функция func()?


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:02
я её развернул в бесконечный цикл с отправкой сигнала. В классе fiber, в методе run().
Собственно это подходит для унифицированной функции. fiber - обертка, в run - унифицированный запуск функции.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:03
я её развернул в бесконечный цикл с отправкой сигнала. В классе fiber, в методе run().
Как вы представляете разворот уже собранной функции из dll в fiber?


Собственно это подходит для унифицированной функции. fiber - обертка, в run - унифицированный запуск функции.
Если бы был доступ к коду, такие чудеса не понадобились бы. :)


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:07
Выходной. Неужели разум на отдыхе?
Варианты:
1)  достаём непосредственно в обертке.
Код:
void run()
{
QLibrary libr("blabla");
/*Тут туфта с доставанием функции, её прототипом*/
func();
}


2) передаём в конструкторе обертки
Код:
fiber::fiber(Указатель на функцию func);
...
void run
{
func();
}

3) глобальный объект
Код:
void run
{
 SingleToneDllPointer.func();
}



Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:12
Выходной. Неужели разум на отдыхе?
Да вот я смотрю что на отдыхе. :)

Код
C++ (Qt)
void run()
{
QLibrary libr("blabla");
/*Тут туфта с доставанием функции, её прототипом*/
func();    // все мы зависли, только убийство нитки нам поможет
}
 

Код
C++ (Qt)
fiber::fiber(Указатель на функцию func);
...
void run
{
func();    // все мы зависли, только убийство нитки нам поможет
}
 

Код
C++ (Qt)
void run
{
SingleToneDllPointer.func();     // все мы зависли, только убийство нитки нам поможет
}
 

А нам нужно определить, что произошел зависон, прервать выполнение этой функции и, думаю, запустить функцию из другой библиотеке.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:25
Ёмой, ты на меня ещё повесь чтоб она и в сортир сходила и смысла за собой.

Прочитай внимательно свою же реплику, в ответ на которую я сделал сей пример... Прочитай.
Цитировать
Вот функция.
Она будет немного долго выполняться, запустите ее пожалуйста как хотите, что бы она через пять секунд вышла. Хотите с исключениями, хотите без.


Я привел тебе набросок, который позволяет остановить любую функцию в любой момент.

Что тебе надо дальше?! Набросок не равняется рабочий и подходящий для вас компонент, но он есть и работает. Узнать почему зависла - невозможно, ибо dll для нас чёрный ящик.

Ещё у данной dll скорее всего интерфейс не ограничивается 1 функцией. Есть и вывод ошибок, некорректных данных и прочего.

В результате:
1) имеется функционал остановки функции в любой момент.
2) у вас имеется описание функции.
3) у вас ещё какие то запросы.

Куда и что вы добавите ваше дело.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:29
Я привел тебе набросок, который позволяет остановить любую функцию в любой момент.
Не привел. Вы что то где то размазали и куда то что вставили.

Код
C++ (Qt)
void func()
{
   qDebug() << "Running...";
   for(;;)
   {
   }
}
 

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


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:30
Йепте, вот опиши её где угодно и вставь её вызов в run. Это ТАК сложно?



Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:30
Йепте, вот опиши её где угодно и вставь её вызов в run. Это ТАК сложно?
Для меня да. Покажите в реальном примере.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:31
Код:

void func()
{
    qDebug() << "Running...";
    for(;;)
    {
    }
}

class fiber
{
// тут остальные методы и код
void fiber::run()
{
func();
}
}

Где проблема? Почему вызов функции у вас вызывает какие-то проблемы невнятные?


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:32
Код:

void func()
{
    qDebug() << "Running...";
    for(;;)
    {
    }
}

class fiber{
void fiber::run()
{
func(); }
}
}
Здесь нельзя остановить нитку fiber без terminate. :)


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:34
Йепте, так в том и дело, что мы используем .... Тараааммм - terminate!
Потому что:
1) Прервать выполнение функции нельзя.
2) Можно terminate потока.
3) Можно убить процесс.

Вариантов больше нет, если не изменять тело функции :D

И да, существенный недостаток вашего сообщения - нигде вы не говорите, что terminate нельзя :)

PS ещё имеется функционал, о котором писал Igors - передача исключения. Я пытался использовать его из-за похожей проблемы, но не получилось чегой то.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:36
2) Можно terminate потока.
Не можно. Частенько это будет приводить к порче основного процесса.
Мы тут все это придумываем с процессами-песочницами, только поэтому. :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:37
И да, существенный недостаток вашего сообщения - нигде вы не говорите, что terminate нельзя :)
Вы правда думали, что кроме вас про terminate никто не слыхал. :)

Кстати, чуть выше задачки я писал:
Но процесс мы можем убить без последствия для других процессов, а вот нитку для процесса не всегда.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:40
Не приводит это к порче процесса. Terminate заставляет поток умереть, но не сразу.
Т.е. могут быть попорчены используемые и передаваемые в функцию переменные. Так же может быть попорчено выделение памяти.

Для переменных достаточно будет создавать "точки восстановления" перед подключением и использованием библиотек.
А вот для порчи памяти нужно что-то придумать, вроде перегрузки new и собственного менеджера.

PS ей богу, вы своё сообщение не прочитали. Ни разу наверно :D Вы не ограничивая никого в средствах бросили вызов. Вызов принят, результат есть, а вы находите уже какие то непонятки аля
Цитировать
"Как вы представляете разворот уже собранной функции из dll в fiber?"
или  
Цитировать
"А нам нужно определить, что произошел зависон, прервать выполнение этой функции и, думаю, запустить функцию из другой библиотеке."
или  же вот этот милый диалог.
Old:
Цитировать
Цитировать
PPS модифицируем пример и вуаля - у вас в обертке вызывается функция с защитой от зависания.
Прекрасно, где же это чудо обертка? Улыбающийся
Я:
Цитировать
Представьте в моем предыдущем сообщении прикреплена ссылка на архив с исходниками, Оо. Или вы её так небрежно не заметили?
ИИИИ... Добивание Old:
Цитировать
Скажите пожалуйста в каком месте вызывается функция func()?
Какая функция? Написано ж про модификацию примера :D

Требуете того, о чем не написали. Сообщения к тому ж не читаете видимо :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:45
Не приводит это к порче процесса. Terminate заставляет поток умереть, но не сразу.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686724%28v=vs.85%29.aspx

Цитировать
The TerminateThread and TerminateProcess functions should be used only in extreme circumstances, since they do not allow threads to clean up, do not notify attached DLLs, and do not free the initial stack. In addition, handles to objects owned by the thread are not closed until the process terminates. The following steps provide a better solution:


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:47
Вы не ограничивая никого в средствах бросили вызов. Вызов принят, результат есть
Да ради Бога. К сожалению результат с terminate никому не интересен, из-за невозможности его практического использования.
 


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:48
Кхм. Вы привели стандартное описание терминайтеда. Где там что страшного написано про порчу процесса?

Приводятся те же проблемы, что привел и я - распил памяти, изменение переменных. Да, ещё вон есть извещение dll о закрытии потока, но я о нем мало что знаю, но что-то подсказывает мне что это штатная и предусмотренная ситуация.

PS если читать документацию - везде рекомендуется, но не запрещается.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:50
Кхм. Вы привели стандартное описание терминайтеда. Где там что страшного написано про порчу процесса?
Нет я привел предупреждение из стандартного описания.
И я ни коем образом никого не отговариваю от его использования. Нормально, значит нормально.


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 15:56
Видел 2 проекта для обработки данных с использованием терминейтеда. Работают спокойно, особо не падают.

Собственно это единственный способ завершить зависший поток, увы. Так же как и kill для процесса.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 15:58
Собственно это единственный способ завершить зависший поток, увы. Так же как и kill для процесса.

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


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 16:38
Можно толочь воду в ступе, а можно сделать 2 проекта и сравнить. :)


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 16:40
Можно толочь воду в ступе, а можно сделать 2 проекта и сравнить. :)
Какие два проекта?


Название: Re: Библиотека-убийца
Отправлено: Bepec от Апрель 13, 2014, 17:12
1 с терминайтедом, второй с процессом.


Название: Re: Библиотека-убийца
Отправлено: Old от Апрель 13, 2014, 17:17
1 с терминайтедом, второй с процессом.
Для чего?
Если OKTA устроит вариант с terminate потока, то хорошо (хотя тогда темы бы этой не было). Для меня лично этот вариант неприемлем.


Название: Re: Библиотека-убийца
Отправлено: OKTA от Апрель 14, 2014, 01:07
Ух вы развели тут, стоило отлучиться на выходные)))) Попробую ответить на все увиденные вопросы разом.
К сожалению, простой terminate потока с либой не поможет, т.к. библиотека динамически хапает память и грохнув поток, вся память занятая останется на месте в лучшем случае(а библиотека может хапать очень много памяти), а в худшем udefined behaviour, т.к. мне неизвестно, что либа творит в памяти)
Ф-ия очистки памяти у библиотеки тоже есть, но она так же останавливается в недрах библиотеки и не возвращает значения.
Обнаружился еще один неприятный момент, который ставит к нулю все попытки выделения либы в отдельный процесс - есть ф-ии, которые действительно долго работают в нормальной библиотеке, а в кривой так же приводят к зависанию,  соответственно различить их в принципе становится невозможно, т.к. я не определю работает либа на самом деле или просто зависла.
Посмотрим, что скажет на это заказчик))
А выделить работу с библиотекой в отдельный процесс это мало того, что жестко, т.к. на универсальность решения рассчитывать не приходится (хотя я нашел статью, где какие-то австралийцы сделали универсальную обертку для работы с либами, но так и не понял как и примера тоже не нашел), а к тому же сама специфика библиотек очень тягостна. Функции возвращают только true/false, а сами данные передаются обратно через параметр функции, но не в классическом виде, когда мы сами выделяем память для значения, а либа сама выделяет память и отдает нам указатели. Я уже заводил тему про это - http://www.prog.org.ru/topic_26764_0.html, если помните и как такое тягать между процессами, я не представляю  :-[
Но спасибо всем за помощь) Завтра на работе решу, что делать)