Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Подвисание при создании потока в хуке, ошибка 1444 - ERROR_INVALID_THREAD_ID 
V
    Опции темы
kami
Дата 17.5.2009, 15:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



В продолжение темы про использование NamedPipes.
По рекомендации dumb вместо пайпов стал использовать MMF.
Работа с mmf производится в доп.потоке, данные добавляются асинхронно.
Проблема:
при аттаче dll в процессы, они подвисают на создании этого доп.потока, обслуживающего mmf.
Подвисают на строках в конструкторе:
Код

constructor TMMFThread.Create(SyncMutexName: string; MMFSize: TDataLength);
var
  i: integer;
begin
  inherited Create(True); // создаем спящим
  FMutexName := SyncMutexName; // инициируем поля
  FMMFSize := MMFSize;
  i := 0;
  FWndHandle:=0;
  Resume; // пробуждаем
  while (not PostThreadMessage(ThreadID, WM_NULL, 0, 0)) and (i < 50) and (not Terminated) do // и ждем пока начнет работать очередь сообщений
// вот на этом цикле и идет подвисание.
    begin
      LogFile.WriteChronoStringCRLF('Wait pause. Error='+IntToStr(GetLastError)); // если работать без счетчика i, то мерзнет абсолютно все.
      Sleep(100);
      inc(i);
    end;
end;

Ошибка в лог выводится каждый раз одна и та же - 1444, ERROR_INVALID_THREAD_ID. Несмотря на то, что в действительности поток создается и работает нормально (данные от него через mmf приходят исправно).
Очередь сообщений доп.потока так же создается и используется:

Код

procedure TMMFThread.Execute;
var
  msg: TMSG;
begin
  PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
  // инициализация всего и вся.
  while not Terminated and GetMessage(msg, 0, 0, 0) do
    if msg.hwnd = 0 then
      case msg.Message of
        msgThreadClose: /
          begin
            Terminate;
            break;
          end;
      else
        DispatchMessage(msg);
      end
    else
      DispatchMessage(msg);
 // деинициализация всего и вся.
end;


тестовый пример - во вложении.

Где я не прав?

Добавлено через 1 минуту и 17 секунд
ай-я, пока редактировал - вложение потерялось :(
вот оно.

Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  mmf_hook.rar 8,34 Kb
PM MAIL WWW   Вверх
MetalFan
Дата 17.5.2009, 16:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



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

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


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
kami
Дата 17.5.2009, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(MetalFan @  17.5.2009,  16:11 Найти цитируемый пост)
на сколько я помню, не рекомендуется делать лишние телодвижения(в т.ч. создавать потоки) в DllMain при загрузке библиотеки...

точно, нашел такое...
DllMain callback function, в ремарках.

Если точнее, то
Цитата

Because DLL notifications are serialized, entry-point functions should not attempt to communicate with other threads or processes. Deadlocks may occur as a result.


А як жеш быть?
imho, лучше 1 раз потерять во времени при инициализации, чем каждый раз на вызове хука для синхронизации обращения к разделяемому ресурсу...

Это сообщение отредактировал(а) kami - 17.5.2009, 16:23
PM MAIL WWW   Вверх
MetalFan
Дата 17.5.2009, 16:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



кстати, а как вообще написана DllMain?


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
kami
Дата 17.5.2009, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(MetalFan @  17.5.2009,  16:11 Найти цитируемый пост)
может стоит крайне упростить код, выполняемый в ней. не очень хорошо пускать цикл, начинать писать в файл, чего-то ждать, имхо.

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

Цикл в конструкторе доп.потока могу убрать, но тогда нет уверенности в том, что при обращении к его методам он будет уже проинициализирован.

Сейчас пришла мысль:

А если инициализацию провести при первом вызове процедуры хука?
Правда, это тоже не рекомендуется - инициализация процесс длительный, Windows может не дождаться его окончания и прервать выполнение hook callback функции...

Добавлено через 3 минуты и 52 секунды
Цитата(MetalFan @  17.5.2009,  16:25 Найти цитируемый пост)
кстати, а как вообще написана DllMain?

Код

  hMap := OpenFileMapping(FILE_MAP_READ, False, @s[1]); // здесь содержатся только идентификаторы хуков.
  if (hMap <> 0) and (hMap <> INVALID_HANDLE_VALUE) then
    begin
      hr := MapViewOfFile(hMap,  FILE_MAP_READ,  0, 0,  SizeOf(THookRec));
      if hr <> nil then
        begin
          Move(hr^, HookRec, SizeOf(THookRec)); // скопировали их (идентификаторы хуков) себе
          UnMapViewOfFile(hr);
          begin
            s := 'Start sending data to main='#13#10;
            if Assigned(f) then
              F.Write(s[1], Length(s));

            if not Assigned(MMFThread) then
              MMFThread := TMMFThread.Create(GetMapName, 1024 * 1024); // непосредственно создание Thread-а обмена
              // именно на его конструкторе и "зависаем".
            MMFThread.AsyncAdd := True;
          end
        end
      else
        begin
          s := 'Cant get map view. Error=' + IntToStr(GetLastError) + #13#10;
          if Assigned(f) then
            F.Write(s[1], Length(s));
        end;
      CloseHandle(hMap);
    end
  else
    begin
      s := 'Cant open file mapping. Error=' + IntToStr(GetLastError) + #13#10;
      if Assigned(f) then
        F.Write(s[1], Length(s));
    end;

PM MAIL WWW   Вверх
MetalFan
Дата 17.5.2009, 16:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



Цитата(kami @  17.5.2009,  16:21 Найти цитируемый пост)
imho, лучше 1 раз потерять во времени при инициализации, чем каждый раз на вызове хука для синхронизации обращения к разделяемому ресурсу...

расшифруй плиз...
в общем тут дело такое - создать то поток можно, но нельзя в него "лезть" из dllmain. а инициализировать можно все в Execute потока.
ибо, как написано у Рихтера, все DllMain вызываются линейно.
и у тебя как раз такая ситуация, что поток не будет запущен, пока не отработает DllMain c DLL_THREAD_ATTACH, а она не запустится, пока не отработает DLLMain с DLL_PROCESS_ATTACH


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
kami
Дата 17.5.2009, 16:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(MetalFan @  17.5.2009,  16:31 Найти цитируемый пост)
расшифруй плиз

Хук пишет данные в mmf, основная программа "выгребает" их.
Чтобы не было накладок (один недописал, второй уже считал и обнулил mmf) идет синхронизация с помощью мьютексов.
Если добавлять данные в mmf непосредственно из потока, в котором вызыван хук, то неизвестно, сколько времени будет потеряно на WaitFor-ожидание, что для хука недопустимо. Посему было сделано так - данные из хука в доп.поток, работающий с mmf, передаются с помощью PostThreadMessage, что не задерживает выполнение хука. А этот доп.поток пускай ждет сколько угодно - его ожидания не лимитируют.

Это и имел ввиду, говоря "лучше день потерять, зато потом за 5 минут долететь"    smile 

Цитата(MetalFan @  17.5.2009,  16:31 Найти цитируемый пост)
и у тебя как раз такая ситуация, что поток не будет запущен, пока не отработает DllMain c DLL_THREAD_ATTACH, а она не запустится, пока не отработает DLLMain с DLL_PROCESS_ATTACH

Ух ты...
спасибо, буду знать.
PM MAIL WWW   Вверх
MetalFan
Дата 17.5.2009, 17:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



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


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
kami
Дата 17.5.2009, 17:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(MetalFan @  17.5.2009,  17:16 Найти цитируемый пост)
неужели это настолько критично?

В условиях данной задачи (имеется ввиду - полной задачи, а не этого упрощения) - некритично.
Но я не люблю что-то сделав, возвращаться потом к тому же вопросу для доработки. (например, в разрабатываемом классе есть ф-и AddData, GetAllData, но нет GetFirstData).
Вдруг в другой задаче нужно будет отправить критически важные данные сразу после создания MMFThread?

Предпочитаю делать что-либо с претензией на какую-никакую, а универсальность  smile 
PM MAIL WWW   Вверх
MetalFan
Дата 17.5.2009, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



кстати... к алгоритму можно придраться... имхо - он не надежен.
ибо Post{Thread}Message не гарантирует доставку сообщения. а ты наверняка передаешь с пом.него данные, которые затем будут очищаться в потоке? а если потоку сказали Terminate, он завершится не обработав возможно ожидающие в очереди сообщения...
в общем мое мнение: сообщения можно здесь использовать только для нотификации, но никак не для передачи важных данных.

Добавлено через 11 секунд
з.ы. конечно же я могу быть не прав


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 17.5.2009, 21:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Подробное описание проблем с DllMain (серия на 4 поста).
Далее, из ERROR_INVALID_THREAD_ID - двойку вам за знание TThread. Поток запускается ТОЛЬКО после выхода из конструктора (в AfterConstruction). Хитроумные манипуляции с Resume здесь не к месту. Вставьте этот код на Execute. Даже, если вы оставите подобный подход - нет гарантии, что поток успеет создастся до вызова PostThreadMessage - вам всё равно нужна доп. синхронизация.
И ещё MetalFan прав насчёт возмодности пропуска сообщений. Для синхронизации потоков надо использовать события, крит. секции и др. объекты.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
kami
Дата 17.5.2009, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(MetalFan @  17.5.2009,  19:41 Найти цитируемый пост)
ты наверняка передаешь с пом.него данные, которые затем будут очищаться в потоке?

Совершенно верно.
PostMessage(msgAddData, integer(pData), DataSize);
Цитата(MetalFan @  17.5.2009,  19:41 Найти цитируемый пост)
а если потоку сказали Terminate, он завершится не обработав возможно ожидающие в очереди сообщения...

Поток будет терминирован, если:
1. Завершено приложение, в которое внедрен хук.
2. Вызывано UnHookWindowsHookEx для всех установленных из dll хуков.

И в том и в другом случае приходящие после этого данные уже не актуальны.
PM MAIL WWW   Вверх
kami
Дата 17.5.2009, 22:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(CodeMonkey @  17.5.2009,  21:53 Найти цитируемый пост)
двойку вам за знание TThread. Поток запускается ТОЛЬКО после выхода из конструктора (в AfterConstruction)

Протестую!
Код

constructor TThread.Create(CreateSuspended: Boolean);
begin
  inherited Create;
  AddThread;
  FSuspended := CreateSuspended;
  FCreateSuspended := CreateSuspended;
  FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID); 
  // ThreadID становится доступен сразу в конструкторе. Инициация потока (CreateThread) произведена, чего ж еще надо?
  // с точки зрения Windows все более чем нормально. С точки зрения Delphi - все основополагающие манипуляции
  // а именно - добавление ThreadProc в список, IsMultiThread:=True так же выполнены в конструкторе TThread.
  if FHandle = 0 then
    raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
end;


А AfterConstruction только и делает, что вызывает Resume при необходимости.
Я же вызывал его в явном виде в своем классе после inherited Create(True). Просветите меня, если это ошибочно.
Цитата(CodeMonkey @  17.5.2009,  21:53 Найти цитируемый пост)
 Вставьте этот код на Execute.

В Execute выполняется код, предназначенный к выполнению в доп.потоке, инициализация данных и ожидание начала работы потока должны происходить не в нем.
Цитата(CodeMonkey @  17.5.2009,  21:53 Найти цитируемый пост)
нет гарантии, что поток успеет создастся до вызова PostThreadMessage - вам всё равно нужна доп. синхронизация.

Как раз-таки этот цикл гарантирует, что:
1. поток запущен и вошел в Execute.
2. Очередь сообщений инициализирована и работает.

Добавлено через 4 минуты и 52 секунды
Цитата(CodeMonkey @  17.5.2009,  21:53 Найти цитируемый пост)
И ещё MetalFan прав насчёт возмодности пропуска сообщений. Для синхронизации потоков надо использовать события, крит. секции и др. объекты.

Тем самым стопоря работу осн.потока.
Самым простым методом синхронизации будет создание окна в доп.потоке и передача данных в него с помощью SendMessage, что гарантирует поступление данных в поток до выхода из оконной процедуры, т.е. до выхода из SendMessage.

Такая возможность заложена, в примере (вложение первого поста) реализована.

Добавлено через 11 минут и 44 секунды
Цитата(CodeMonkey @  17.5.2009,  21:53 Найти цитируемый пост)
Подробное описание проблем с DllMain (серия на 4 поста)

Уже понял из msdn.
Кошмар!
dll придется пересматривать :(

Это сообщение отредактировал(а) kami - 17.5.2009, 22:14
PM MAIL WWW   Вверх
MetalFan
Дата 18.5.2009, 12:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



Цитата(kami @  17.5.2009,  22:14 Найти цитируемый пост)
Цитата(CodeMonkey @  17.5.2009,  21:53 Найти цитируемый пост)
Для синхронизации потоков надо использовать события, крит. секции и др. объекты. 

Тем самым стопоря работу осн.потока.

ну уж извините) и рыбку съесть и....  не получится. либо синхронизация либо возможная порча данных. а синхронизация с пом. SendMessage конечно проста, но имхо не самый быстрый и надежный вариант.

Это сообщение отредактировал(а) MetalFan - 18.5.2009, 12:40


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 18.5.2009, 13:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Цитата
Тем самым стопоря работу осн.потока.

Цитата
ну уж извините) и рыбку съесть и....  не получится

Нет, почему же: MsgWaitForMultipleObjects (см. также TThread.WaitFor). 
Да даже, если просто тупо WaitForSingleObject - там "завис"-то будет в сотые доли секунды. И уж всяко меньше вашего Sleep(100). Что, долго потоку раскручиваться, что-ли?

Цитата
Я же вызывал его в явном виде в своем классе после inherited Create(True). Просветите меня, если это ошибочно.

А о том, что Resume в AfterConstruction вызывается - вы не подумали?
Такие действия надо делать так:
Цитата
  FThread := TThread.Create(...);
  ...
  WaitForThreadToBeReady(FThread);
  // do something


Цитата
Как раз-таки этот цикл гарантирует, что

Да, что-то я не так этот код прочитал  smile 
Тогда проверяйте свой код - должен работать. Может, конечно, первая итерация и с ERROR_INVALID_THREAD_ID будет, но вторая - успешно.
Что-то мне кажется, вы с i напутали.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 18.5.2009, 14:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



Цитата(CodeMonkey @  18.5.2009,  13:43 Найти цитируемый пост)
А о том, что Resume в AfterConstruction вызывается - вы не подумали?

а что в этом плохого, если поток и так запущен?


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 18.5.2009, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Цитата
а что в этом плохого, если поток и так запущен?

За исключением того, что мы городим кривой код на ровном месте - ничего ;)


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 18.5.2009, 17:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



CodeMonkey, 
ну с одной стороны, делать Resume в конструкторе TThread нам ничего не мешает, но с другой - это нарушает идеология самого класса...


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
kami
Дата 18.5.2009, 18:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(CodeMonkey @  18.5.2009,  13:43 Найти цитируемый пост)
А о том, что Resume в AfterConstruction вызывается - вы не подумали?

Подумал давно, и тогда же посмотрел.
Код

procedure TThread.AfterConstruction;
begin
  if not FCreateSuspended then // если создали не "спящим",
    Resume; // то пробуждаем.
// а если спящим (мой случай) - ничего не делаем.
end;

И зачем мне перекрывать еще и этот метод? Не вижу разницы в вызове Resume в AfterConstruction или в конструкторе после inherited.

Цитата(CodeMonkey @  18.5.2009,  13:43 Найти цитируемый пост)
Да даже, если просто тупо WaitForSingleObject - там "завис"-то будет в сотые доли секунды.

Вопрос:
а что ждать?
В конструкторе ничего не создается.
В процедуре потока - мьютекс, MMF и окно. Но! Они могут быть не-инициализированы даже после отработки AfterConstruction, ибо кто кроме планировщика потоков Windows может знать, когда управление в первый раз будет отдано в этот новый поток?
Цитата(CodeMonkey @  18.5.2009,  13:43 Найти цитируемый пост)
Тогда проверяйте свой код - должен работать.

Теперь, с учетом 
Цитата(MetalFan @  17.5.2009,  16:11 Найти цитируемый пост)
не рекомендуется делать лишние телодвижения (в т.ч. создавать потоки) в DllMain при загрузке библиотеки...

работает. Правда, одно лишнее телодвижение осталось - создание потока. Вот только без ожидания его инициализации. Потокобезопасные процедуры работы с ним позволяют безболезненно обойти это, за исключением 2-х моментов:
1. поток создан, но данные в execute не инициализированы. В этом случае утечек нет.
2. Поток жестко терминирован. Утечки будут. Малого размера, но будут.
PM MAIL WWW   Вверх
MetalFan
Дата 18.5.2009, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 16
Всего: 128



Цитата(kami @  18.5.2009,  18:42 Найти цитируемый пост)
Малого размера, но будут. 

тебя это, похоже, не должно беспокоить...

Цитата(kami @  17.5.2009,  21:55 Найти цитируемый пост)
Совершенно верно.
PostMessage(msgAddData, integer(pData), DataSize);
Поток будет терминирован, если:
1. Завершено приложение, в которое внедрен хук.
2. Вызывано UnHookWindowsHookEx для всех установленных из dll хуков.

И в том и в другом случае приходящие после этого данные уже не актуальны. 

т.е. необработанное сообщение приведет опять же к небольшой утечке памяти.


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
kami
Дата 18.5.2009, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(MetalFan @  18.5.2009,  20:27 Найти цитируемый пост)
тебя это, похоже, не должно беспокоить

Да.
Я не думаю, что утечка в 2*SizeOf(integer) - большая проблема для чужого приложения. Даже случившаяся несколько раз.
Цитата

Вызывано UnHookWindowsHookEx для всех установленных из dll хуков.

Небольшая поправка:
вызов UnHookWindowsHookEx не приведет к моментальной выгрузке dll из адресного пространства всех процессов, но хуки уже вызываться не будут.
PM MAIL WWW   Вверх
CodeMonkey
Дата 18.5.2009, 23:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Цитата(kami @  18.5.2009,  21:46 Найти цитируемый пост)
Я не думаю, что утечка в 2*SizeOf(integer) - большая проблема для чужого приложения

На сервере подкачка = смерти ;)


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
kami
Дата 18.5.2009, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(CodeMonkey @  18.5.2009,  23:30 Найти цитируемый пост)
На сервере подкачка = смерти ;)

/me тяжко вздыхает.
Знаю. Читал. Стараюсь свести к минимуму.
Но синхронизацию при добавлении данных использовать не могу. В данном случае.

В любом случае - огромное спасибо MetalFan и CodeMonkey за помощь.
Без вас наверное, до сих пор зависал бы на конструкторе потока, пытаясь понять отчего же он не работает.

Кстати, это может объяснить и неработоспособность компонентов-оберток над namedPipes, которые и послужили началом разбирательства на предыдущую и эту темы.
PM MAIL WWW   Вверх
dumb
Дата 19.5.2009, 02:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 7
Всего: 158



kami, я правильно понимаю: избегая "блокировки" на "ожидании" мьютекса, ты создаешь поток, чтобы "быстро" туда постить инфу?
тогда тебе удалось сделать из мухи здоровенного такого африканского слона. smile

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

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

Цитата(kami @  18.5.2009,  23:41 Найти цитируемый пост)
Но синхронизацию при добавлении данных использовать не могу. В данном случае.
сдается, что в данном случае такая категоричность безосновательна.

"Premature optimization is the root of all evil" (с)

PM MAIL   Вверх
CodeMonkey
Дата 19.5.2009, 08:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Мне тоже кажется, что вы что-то не то делаете, но мне как-то лень копаться  smile 
В общем случае надо бы убрать всё из DllMain, все вещи инициализировать по первому обращению, а глобальные ресурсы хранить в глоб. переменных/threadvar/списке и удалять при выгрузке DLL. Плюс предусмотреть ситуацию переустановки хука без выгрузки DLL.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
kami
Дата 19.5.2009, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(dumb @  19.5.2009,  02:48 Найти цитируемый пост)
 избегая "блокировки" на "ожидании" мьютекса, ты создаешь поток, чтобы "быстро" туда постить инфу?

Нет, этого я  не избегаю.
Работа доп.потока организована в строгом соответствии с Вашими рекомендациями в предыдущей ветке.
А вот добавление данных из другого потока сделано как PostMessage(hwnd, msgAddData, integer(@Data), DataSize);

Цитата(dumb @  19.5.2009,  02:48 Найти цитируемый пост)
если между захватом мьютекса(WaitForSingleObject) и его освобождением(ReleaseMutex) будут только элементарные операции копирования кусков памяти,

Именно так.

Цитата(CodeMonkey @  19.5.2009,  08:37 Найти цитируемый пост)
Мне тоже кажется, что вы что-то не то делаете

Спорить не буду, т.к. учусь, в основном - на своих ошибках smile.
Цитата(CodeMonkey @  19.5.2009,  08:37 Найти цитируемый пост)
но мне как-то лень копаться

Согласен, чужой код, как и душа - потемки.

Цитата(CodeMonkey @  19.5.2009,  08:37 Найти цитируемый пост)
В общем случае надо бы убрать всё из DllMain

Уже думал, попробую и этот вариант.
Цитата(CodeMonkey @  19.5.2009,  08:37 Найти цитируемый пост)
Плюс предусмотреть ситуацию переустановки хука без выгрузки DLL.

Ага, для меня сейчас это самое узкое место.

PM MAIL WWW   Вверх
CodeMonkey
Дата 19.5.2009, 14:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 16
Всего: 89



Цитата
Ага, для меня сейчас это самое узкое место.

Как-то так:

DLL:
Код
var
  SavedHandle: THandle;
  GlobalData: PSomeStruct;  

  Threads: array of TThread; // и т.п.

procedure HookHandler(...);
begin
  if Assigned(GlobalData) and (GlobalData^.Handle <> SavedHandle) then
  begin
    DeleteHookData; // + стоп всего
    SavedHandle := 0; // внутри DeleteHookData
  end;
  if GlobalData = nil then
  begin
    CreateHookData; // + старт всего
    SavedHandle := GlobalData^.Handle; // внутри CreateHookData
  end;

  // работа хука
end;

// DllProc:
begin
  // при process detach:
  DeleteHookData; // + стоп всего
  SavedHandle := 0; // внутри DeleteHookData
end;


App:
Код
var
  GlobalData: PSomeStruct;  

  CreateHookData;
  GlobalData^.Handle := // любое значение, уникально идентифицирующее хук. Например, ровно описатель хука от SetWindowsHookEx
...
  GlobalData^.Handle := 0;
  DeleteHookData;


Добавлено через 3 минуты и 8 секунд
Немного непонятно, на что конкретно ставиться хук. В принципе, если хук, скажем, на GetMessage, то вместо DeleteHookData при process detach можно делать broadcast сообщения, по которому отцепляется DeleteHookData. Ну и в DLLProc вызов всё же оставить - на всякий пожарный.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
dumb
Дата 19.5.2009, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


sceloglauxalbifacies
****


Профиль
Группа: Экс. модератор
Сообщений: 2929
Регистрация: 16.6.2006

Репутация: 7
Всего: 158



народ, не настаиваю, но может таки на "ты"? - общение все же не официальное.

Цитата(kami @  19.5.2009,  13:06 Найти цитируемый пост)
Нет, этого я  не избегаю.
для чего тогда вообще создается доп.поток в контексте чужого процесса? - из обработчика хука сразу класть в mmf структуру.

Цитата(kami @  19.5.2009,  13:06 Найти цитируемый пост)
Работа доп.потока организована в строгом соответствии с Вашими рекомендациями в предыдущей ветке.
эм. я насчет доп.потока ничего не говорил. сейчас, исходя из того, что вижу в коде hlibstaex, еще раз скажу: не нужен доп.поток.
PM MAIL   Вверх
kami
Дата 19.5.2009, 17:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 15
Всего: 72



Цитата(dumb @  19.5.2009,  16:02 Найти цитируемый пост)
народ, не настаиваю, но может таки на "ты"? - общение все же не официальное.

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

Цитата(dumb @  19.5.2009,  16:02 Найти цитируемый пост)
исходя из того, что вижу в коде hlibstaex, еще раз скажу: не нужен доп.поток.

Ок, переделать из потока в обычный класс, обслуживающий mmf - небольшая проблема. Попробую.

Вах!
Цитата(dumb @  19.5.2009,  16:02 Найти цитируемый пост)
исходя из того, что вижу в коде hlibstaex, 

а это как?
Присоединённый файл ( Кол-во скачиваний: 1 ) - это ж я скачивал, чтобы проверить работоспособность ссылки  smile  smile 

Цитата(CodeMonkey @  19.5.2009,  14:14 Найти цитируемый пост)
Как-то так:

Примерно так и думал.
Единственное - до этого времени не держал открытой GlobalData.
PM MAIL WWW   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: WinAPI и системное программирование"
Snowybartram
MetalFanbems
PoseidonRrader
Riply

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Delphi обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • 99% ответов по WinAPI можно найти в MSDN Library, оставшиеся 1% здесь

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема »


 




[ Время генерации скрипта: 0.0920 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.