Queue-таймер вылетает...

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Queue-таймер вылетает...

Сообщение Адская_Капча » 25.11.2015 (Ср) 12:44

Хотелось бы сделать хороший (легковесный, не содержащий в своем составе множество всякой всячины, например, как в DoEvents), точный (хотя бы в пределах одной или нескольких миллисекунд) и не блокирующий основной поток таймер.
Например, в целях каких-то периодических действий или использования паузы (Sleep - блокирующий).
В сети существует следующий пример использования данного таймера:

Код: Выделить всё
' This project requires a Form and a Module
' The Form must have two command buttons (Command1
'  and Command2) on it.
'
'In a form
Private Declare Function CreateTimerQueue Lib "kernel32.dll" () As Long
Private Declare Function CreateTimerQueueTimer Lib "kernel32.dll" (ByRef phNewTimer As Long, ByVal TimerQueue As Long, ByVal Callback As Long, ByVal Parameter As Long, ByVal DueTime As Long, ByVal Period As Long, ByVal Flags As Long) As Long
Private Declare Function DeleteTimerQueue Lib "kernel32.dll" (ByVal TimerQueue As Long) As Long
Private Declare Function DeleteTimerQueueTimer Lib "kernel32.dll" (ByVal TimerQueue As Long, ByVal Timer As Long, ByVal CompletionEvent As Long) As Long
Private hQueue As Long
Private hTimer As Long
Private Sub Form_Load()
    'KPD-Team 2002
    'URL: http://www.allapi.net/
    'E-Mail: KPDTeam@allapi.net
    hQueue = CreateTimerQueue()
    Command1.Caption = "Start"
    Command2.Caption = "Stop"
End Sub
Private Sub Form_Unload(Cancel As Integer)
    DeleteTimerQueue hQueue
End Sub
Private Sub Command1_Click()
    If hTimer = 0 Then
        CreateTimerQueueTimer hTimer, hQueue, AddressOf TimerCallBack, ByVal 0&, 0, 50, 0
    End If
End Sub
Private Sub Command2_Click()
    If hTimer <> 0 Then
        DeleteTimerQueueTimer hQueue, hTimer, ByVal 0&
        hTimer = 0
    End If
End Sub

'In a module
Public Sub TimerCallBack(ByVal lpParameter As Long, ByVal TimerOrWaitFired As Long)
    Debug.Print "Timer callback..."
End Sub


Однако, если сделать интервал таймера 50 мс, схватить за форму мышью и начать ей выписывать различные загогулины, программа вылетит (в IDE), при этом показав примерно следующее:

Инструкция по адресу "0x0fb9c40c" обратилась к памяти по адресу "0x00000014". Память не может быть "written".

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

Если устанавливать флаг WT_EXECUTELONGFUNCTION - количество вылетов снизилось, но они не прекратились.

В чем здесь может быть дело? Думаю, в потоках?

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

Но загогулины выписывать формой нужно.

Здесь (viewtopic.php?f=1&t=24065) говорится про то, что нужно использовать SetTimer, но его тоже не хочется использовать, т.к. точность у него хуже.

Как быть?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 25.11.2015 (Ср) 13:28

Адская_Капча писал(а):С многопоточностью не хотелось бы связываться, потому что Хакер говорит, что стабильной многопоточности не существует.


Я такое не говорил точно. Она существует, и ближайшие примеры её существования: проекты типа ActiveX DLL и ActiveX EXE.

Ещё раз повторю то, что уже неоднократно писал.

Для каждого потока, с которым рантайму предстоит работать, рантайм держит набор потоко-специфичных данных. Структура, в которой хранятся эти потоко-специфичные данные называется EBTHREAD. Почему EB? Потому что VB развился из VBA, а VBA на ранних этапах развития назывался Excel Basic (экселевский бейсик). Так вот эта структура содержит массу потоко-специфичных данных, а указатель на неё хранится в TLS-слоте.

Всякий раз, когда рантайму нужна эта структура, он вызывает TlsGetValue и получает указатель на эту структуру, а затем обращается к нужном полю этой структуры. В твоём случае TlsGetValue вернула 0, а рантайм попытался обратиться к полю структуры по смещению 0x14, отсюда и
адресу "0x00000014". Память не может быть "written".


Но дело в другом. Представим себе, что малюсенькая VB-шная библиотека была волею судеб подгружена внутрь процесса, в котором аж 180 потоков. Стало быть, рантайму на каждый поток нужно выделить и заполнить свою структуру EBTHREAD? Даже если только 1 из 180 потоков реально будет взаимодействовать с VB-шной библиотечкой и только в одном из потоков выполнение зайдёт внутрь рантайма?

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

По сути, это два типа ситуаций: это потоки, которые создаёт сам рантайм (он это делает в случае ActiveX EXE), или потоки, которые присоединяют к рантайму (это когда некий неизвестный рантайму доселе поток вдруг создал экземпляр VB-шного класса из ActiveX DLL).

Помимо того, что рантайм имеет набор собственных потоко-специфичных данных (общих для всего рантайма), каждый VB-шный проект, находящийся в памяти (то есть это скомпилрованный VB-шный EXE или VB-шная DLL или OCX) тоже имеет набор своих потоко-специфичных данных.

И потоко-специфичные данные отдельно взятого проекта тоже не создаются как только новый поток появляется на горизонте: они создаются только тогда, когда станет нужно. Такой наборчик потоко-специфичных данных, если представить проекты как строки в таблице, а потоки как столбцы, то это будет клетка таблицы на пересечении соответствующей строки и столбца — я называю его «контекст».

Так вот, если просто создать новый поток с помощью CreateThread (либо если его создаст система), то ни структура EBTHREAD, ни контекст — не будут созданы. Это как раз твой случай.

Но это не значит, что они вообще никогда не создаются. В проектах типа ActiveX DLL когда новый объект порождается из другого (нового) потока всё корректно инициализируется. А в проектах ActiveX EXE вообще сам EXE порождает новые потоки и всё, опять таки, корректно инициализируется. Ну а для проектов типа Standard EXE возможности создавать новые потоки не предусмотрели, и чтобы этот недостаток восполнить, я и делал свой многопоточный кирпич, но это уже отдельная история.

_______________

Теперь подойдём с другой стороны.

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

Потому что если она будет вызвана в контексте какого-то левого потока, то в нём не будет ни подготовленной EBTHREAD, ни контекстов проектов, а значит, если код callback-функции обратится к рантайму, то будет исключение.

Если документация явно не указывает, в контексте какого или каких потоков будет вызываться callback-фукнция, то надо включать мозг и анализировать. Скорее всего, если ничего не указано, callback-функция будет вызывать в контексте каких-попало потоков. Чтобы она вызывалась в контексте именно того потока, в рамках которого был создан таймер, нужно банальное условие: должен быть код, который вызовет эту функцию, и этому коду должны передавать управление мы сами.

А это сильно сужает дело. Это значит, что если мы хотим создать таймер, а потом погрузиться в бесконечный цикл обсчёта какой-нибудь математики, то просто не существует возможности, что callback-фукнция вдруг начнёт выполняться, неведомым образом прервав большой цикл обсчёта математики.

Существует только 2 способа того, как callback-функция может выполняться в рамках текущего проекта:
  • Как результат работы цикла прокачки оконных сообщений. Это именно тот случай, который использует SetTimer. Поток, создавший таймер, крутит цикл оконных сообщений. И вдруг в этом цикле обнаруживается сообщение WM_TIMER. Наш код (в общем случае, но в случае программирования на VB — обычно не наш, а код самого рантайма, но возможно, что и наш тоже) вызывает DispatchMessage, а она вызывает WindowProc соответствующего получателя сообщения, а WindowProc вызывает callback-функцию.
  • Либо через механизм APC (Asynchronous Procedure Call), но для этого наш поток должен войти в состояние alertable waiting, например, с помщью функции SleepEx.

А теперь подумай над своей ситуацией и ещё раз почитай про CreateTimerQueueTimer.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 25.11.2015 (Ср) 14:11

Хакер писал(а):Я такое не говорил точно

viewtopic.php?p=6778362#p6778362 - вот этот пост, где говорится о том, что нету стабильной многопоточности в Standart Exe, а я делаю именно этот тип проекта и не хочу использовать другие, и dll-ки в том числе :(

Про многопоточность - у меня был где-то пример, который в Standart Exe ее использует, там как раз был трюк с обертыванием параметров в TLS.
Причем вылетов небыло замечено ни в IDE, ни в скомпилированном виде (во всяком случае). Но у себя не могу его найти и потом вы пишете в том посте о том, что
Хакер писал(а):НЕ БУДЕТ НИКАКОЙ стабильной многопоточности в Standard EXE

Поэтому все равно, с многопоточностью иметь дело расхотелось...

Хакер писал(а):я и делал свой многопоточный кирпич

Хотелось бы на него взглянуть, если это можно, конечно. Здесь на сайте не могу его найти.

Хакер писал(а):SleepEx

Может, уж лучше тогда ZwDelayExecution? Хотя он вроде блокирующий...

Над ситуацией и над вашим ответом подумаю, однако мне с 1 раза не удалось как следует вникнуть в суть поста...

Видимо, не существует легкого и изящного решения проблемы таймеров?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 25.11.2015 (Ср) 15:35

Адская_Капча писал(а):вот этот пост, где говорится о том, что нету стабильной многопоточности в Standart Exe

Без обёртывания кода, который должен в другом потоке, в ActiveX DLL — штатно из коробки нет.

Адская_Капча писал(а):Хотелось бы на него взглянуть, если это можно, конечно. Здесь на сайте не могу его найти.

Он не доделан и теперь, по прошествии 4 лет, проблема помимо его доделки состоит в том, чтобы вспомнить, на чём остановилось дело.

Адская_Капча писал(а):Может, уж лучше тогда ZwDelayExecution? Хотя он вроде блокирующий...

SleepEx это и есть переходник к Nt(Zw)DelayExecution. Они блокирующие, но вызов с нулевым интервалом позволяет протолкнуть очередь APC.

Кроме того, остаётся «типичный» для данного случая выход (который я ждал, что посоветует The trick, пока я ездил по делам) — написать callback так, чтобы исключить использование рантайма.

Адская_Капча писал(а):однако мне с 1 раза не удалось как следует вникнуть в суть поста...

Даю ещё один намёк: посмотри на флаг WT_EXECUTEINTIMERTHREAD.

Адская_Капча писал(а):Видимо, не существует легкого и изящного решения проблемы таймеров?

Да ты сначала дай ответ: как бы ты хотел быть уведомлён о наступлении нужного момента.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 25.11.2015 (Ср) 16:19

Я позже отпишу, пока что на работе (в командировке).
Кстати ты вообще пробовал мой метод (тот с которого ты кинул ссылку на пост хакера о стабильности)? Он не работает в твоём случае?
Насчёт ide - я думаю вообще не стоит заниматься отладкой многопоточных программ там. Она не предназначена для этого, даже activex exe работают в том же потоке при отладке, а пример Курлянда - это вообще фигня полная которая ещё более нестабильная.
UA6527P

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 25.11.2015 (Ср) 21:19

Хакер тут писал(а):Вообще, самым правильным будет засунуть мою функцию CreateBasicThread в рантайм, где ему и место.


А рантайм ведь загружается в память при запуске VB-программы? Что если пропатчивать рантайм прямо в памяти, добавив эту самую функцию CreateBasicThread?

Хакер тут писал(а):Вот с сишном рантайме _beginthread ведь сидит в самом рантайме, а не распростаняется в виде отдельного исходника или отдельной библиотеки

Библиотека сишного рантайма вроде бы есть на большинстве ОС семейства Windows NT?
Может, тогда имеет смысл пользоваться экспортируемой функцией создания потока из нее, чтобы не шаманить с VB-шным рантаймом?


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

Про какие такие трюки идет речь?

Хакер тут писал(а):и забота о том, чтобы кирпич работал со всеми известными науке версиями (билдами) библиотеки MSVBVMx0.dll (включая, кажется, даже 5-ую версию), и даже такое устройство кирпича, что он способен обеспечить стабильную многопоточность даже в том случае, если в АП одного и того же процесса окажутся загруженными несколько разных скомпилированных VB-проектов, каждый из которых нуждается в многопоточности, и каждый из которых использует разную версию рантайм-библиотеки (за счёт SxS-перенаправления или за счёт переименования библиотеки в импорте — тут вот есть товарищи, которые хотят избавиться от импорта msvbvm, а были и такие, которые хотели её переименовать в, к примеру, fun.dll, поменяв имя файла DLL и подправив таблицу импорта).

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

Хакер здесь писал(а):подправив исходники IDE так, чтобы в режиме Standard EXE параметр «Threading Model» не блокировался, и автор проекта мог по желанию выбрать использование TLS для глобальных переменных.

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


Хакер писал(а):работы цикла прокачки оконных сообщений

У меня были такие идеи:
1) Просабклассить hwnd формы. Оконные сообщения идут. Если в программе ничего не делать, между вызовами оконных сообщений проходит достаточно времени. Если начать двигать форму, частота появления оконных сообщений резко увеличивается. Получается некая "неравномерность", что не очень хорошо...
2) Просабклассить чандермейн (самый главный hwnd). Однако оконные сообщения при этом совсем не возникают, если в программе ничего не делать... Частота их появления здесь намного реже.

Хакер писал(а):наш поток должен войти в состояние alertable waiting, например, с помщью функции SleepEx.

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

Хакер писал(а):вызов с нулевым интервалом позволяет протолкнуть очередь APC.

Просто единожды вызвать с нулевым интервалом и все? Вызвать в самой callback-функции или это неверное предположение?

Хакер писал(а):WT_EXECUTEINTIMERTHREAD

Все равно вылетает... И при WT_EXECUTEINPERSISTENTTHREAD тоже. Подозреваю, что судя по всему, должны быть еще какие-то особые манипуляции, помимо простой подстановки флага в вызов CreateTimerQueueTimer из исходного примера?

Хакер писал(а):дай ответ

Даю: пока это не имеет принципиального значения, либо мне еще не все программистские премудрости известны...
Уведомления о наступлении нужного момента могут быть сделаны не только через callback-функции?
Я не против ассемблерных вставок, можно с вызовами по указателю еще что-то пришпандурить...
Благо выделять память с помощью хипа и создавать на лету ассемблерные вставки сейчас делать умею и использую Изображение

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 25.11.2015 (Ср) 21:34

Адская_Капча писал(а):А рантайм ведь загружается в память при запуске VB-программы?

Рантайм загружается в память на правах обычной DLL. При старте импортируещего модуля. Да, загружается.

Адская_Капча писал(а):Что если пропатчивать рантайм прямо в памяти, добавив эту самую функцию CreateBasicThread?

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

Адская_Капча писал(а):Может, тогда имеет смысл пользоваться экспортируемой функцией создания потока из нее, чтобы не шаманить с VB-шным рантаймом?

Абсолютно бессмысленное предложение, говорящее о том, что всё вышенаписанное ты не понял вовсе. Воспользоваться функцией _beginthread из отдельно лежащего сишного рантайма можно, и это действительно создаст новый поток. Но структура EBTHREAD от этого не появится, и контекст проекта от этого тоже не инициализируется, и VB-шный код, работающий в рамках нового потока, как падал, так и будет падать.

Адская_Капча писал(а):Про какие такие трюки идет речь?

О любых.

Адская_Капча писал(а):Думаю, пока можно обойтись и без этого, на первое время... Понятно, что хочется сделать все наиболее универсально. Однако вероятность использования одновременно разных версий MSVBVMx0.dll и прочего, что упомянуто в цитате, все таки крайне мала.

Я не умею писать неправильный код. У меня в коде кирпича не может быть переменной «указатель на функцию XXX», если я знаю, что в каждом рантайме функция XXX лежит в разных местах. Я уже начал писать кирпич правильным образом и он практически дописан.

Насколько я помню, недоделанной там осталось две вещи: Sub-Main-supression (чтобы в новом потоке не вызывался Sub Main) и правильное завершение цикла прокачки сообщений главного потока при завершении созданных из него дочерних потоков.

Адская_Капча писал(а):А может, нам всем собраться и сделать петицию в Микрософт, чтобы они отдали исходники? Все равно ведь не поддерживают VB6, что им сейчас терять? В то же время существует практика, когда исходники чего-то старого отдаются "на растерзание".

Были уже такие петиции. MS на них плевать хотела. Есть идея получше, но я её пока оставлю при себе.

Адская_Капча писал(а):У меня были такие идеи:
1) Просабклассить hwnd формы. Оконные сообщения идут. Если в программе ничего не делать, между вызовами оконных сообщений проходит достаточно времени. Если начать двигать форму, частота появления оконных сообщений резко увеличивается. Получается некая "неравномерность", что не очень хорошо...
2) Просабклассить чандермейн (самый главный hwnd). Однако оконные сообщения при этом совсем не возникают, если в программе ничего не делать... Частота их появления здесь намного реже.

Вообще не понял, к чему это.

Адская_Капча писал(а):Там, вроде бы, используются только флаг алертабле и значение задержки, больше параметров нету.

А какие ещё нужны?

Адская_Капча писал(а):Просто единожды вызвать с нулевым интервалом и все?

Вызывать её во всех местах, где предполагается, что нормальное выполнение кода должно быть прервано. Почти как DoEvents. Но лучшим решением было бы всё-таки использование примитива синхронизации. Чисто с точки зрения производительности.

Адская_Капча писал(а):Все равно вылетает...

Поставь в отладчике брекпоинт на callback-е и посмотри, в каком потоке идёт вызов. Видимо не в том, что создал таймер. Значит это не подходящий флаг и правильный подход состоит не в использовании APC, а в использовании примитива синхронизации.

Адская_Капча писал(а):Даю: пока это не имеет принципиального значения, либо мне еще не все программистские премудрости известны...
Уведомления о наступлении нужного момента могут быть сделаны не только через callback-функции?
Я не против ассемблерных вставок, можно с вызовами по указателю еще что-то пришпандурить...
Благо выделять память с помощью хипа и создавать на лету ассемблерные вставки сейчас делать умею и использую Изображение


Ответ абсолютно не в тему. Перечитай вопрос и попытайся понять его истинный смысл.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 25.11.2015 (Ср) 21:36

И отдельно: не надо писать ссылку на цитируемый пост в отдельном блоке [quote]. Вставляй URL цитируемого поста в параметр тега quote — посмотри, как я поправил твой пост.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 26.11.2015 (Чт) 11:17

The trick писал(а):Насчёт ide - я думаю вообще не стоит заниматься отладкой многопоточных программ там.

А отладка многопоточных программ в IDE и просто работа многопоточных программ в IDE без отладки - это не одно и то же?
Мне не столько нужна многопоточность, сколько хочется сделать хороший таймер... Может, его можно сделать и без многопоточности?
The trick, в ваших примерах еще предстоит разобраться, пытаясь как-то их применить по отношению к созданию таймера. Ну пишет, что в IDE не будет работать...
Очень желательно, чтобы таймер работал и под IDE, конечно... Зачастую, приходится выполнять программы прямо в IDE. В среде VBA также может понадобиться таймер. В ряде случаев, без пакета MS Office не обойтись, так как нет смысла писать на VB свой аналог MS Office. Можно попробовать, конечно, но на это уйдет громадное количество времени. Да еще если в одиночку его реализовывать...

The trick писал(а):а пример Курлянда - это вообще фигня

У меня какой-то другой пример был, не Курланда...

Хакер писал(а):добавлять эту функцию во время выполнения

Ассемблерные вставки формирую во время процедуры инициализации (самая первая выполняющаяся в программе процедура), сохраняя в массив указатели на них, а уж потом их использую. Разве нельзя сделать по аналогии?

Хакер писал(а):Но структура EBTHREAD от этого не появится

А она, значит, должна появляться непременно посредством вызова из DLL? Я к тому, чтобы не делать свою DLL, а просто воспользоваться сишным рантаймом, а в самой программе уже "доделать" всё недостающее.

Хакер писал(а):О любых.

А формирование и использование ассемблерных вставок к ним относится?

Хакер писал(а):если я знаю, что в каждом рантайме функция XXX лежит в разных местах

Разве еще есть кто-то, кто использует рантайм 5-й версии? А что касается 6-го - неужели они тоже встречаются разные и функции могут лежать в разных местах?

Хакер писал(а):цикла прокачки сообщений главного потока

Можно ли к нему как-то подобраться или получить его в VB? Если не главного, то дополнительного потока. Может, тогда отпадает необходимость создавать таймеры? Что если как-то приаттачиться к этому циклу, проверяя метки времени в дополнительной процедуре, и если временной лимит достигнут, делаются какие-то действия или дальнейшие проверки завершаются (одноразовый ждущий таймер). Собственно, это и имелось ввиду к ответу на:
Хакер писал(а):Вообще не понял, к чему это.

"Просабклассить hwnd" - разве это не попытка подобраться к циклу сообщений, или это вовсе не он?

Хакер писал(а):Поставь в отладчике брекпоинт на callback-е

Мне еще нужно умудриться найти этот самый момент... А отладка P-кода и поиск чего-либо в нем - это просто кошмар на улице Вязов. Все-таки мне хотелось, чтобы таймер работал и в режиме IDE.

Хакер писал(а):использовании примитива синхронизации.

Неименованные мьютексы?

Хакер писал(а):Есть идея получше, но я её пока оставлю при себе.

Кажется, я догадываюсь, что это за идея =)
Здесь можно только пожелать удачи...

Хакер тут писал(а):не надо писать ссылку на цитируемый пост в отдельном блоке

Уррра! Наконец-то теперь понятно, как решить эту проблему с добавлением URL! Классный трюк со вложенным bb-тегом, который мне не был известен. Теперь буду вовсю юзать его Изображение

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 26.11.2015 (Чт) 12:13

Адская_Капча писал(а):А отладка многопоточных программ в IDE и просто работа многопоточных программ в IDE без отладки - это не одно и то же?

Не понял к чему это. Работа кода в IDE и есть отладка. Если имеется в виду любые программы, т.е. уже скомпилированные то они могут прекрасно работать в IDE, можешь посмотреть мой пост про создание DLL, там потоки создаются без проблем.
Адская_Капча писал(а):Мне не столько нужна многопоточность, сколько хочется сделать хороший таймер... Может, его можно сделать и без многопоточности?

Ты так и не сказал каким образом ты хочешь делать уведомления. Как писал Хакер, если у тебя будет большой и долгий цикл, в котором выполняются тяжелые вычисления как ты собираешься прерывать вычисления и переходить на колбэк? Я думаю, конечно можно подменить контекст из другого потока, а по окончании вернуться туда, откуда закончили, но тут тоже не все так просто, нужно сохранять контекст и задействовать обработку исключений, которая тоже довольно-таки занимает большое время. А также возможны другие "подводные камни", которые вылезут по ходу.
Адская_Капча писал(а):Очень желательно, чтобы таймер работал и под IDE, конечно...

Ну так сделай 2 версии, в IDE обычный таймер будет отрабатывать, а в скомпилированном виде то что ты там затеял. С помощью debug.assert определяй режим.
Адская_Капча писал(а):одноразовый ждущий таймер

Я уже делал класс ожидания с асинхронным уведомлением, там кстати есть пример с таймером. Если тебе нужен будет циклический таймер, то можно немного изменить код, чтобы второй поток не завершался, а постоянно ожидал и гененрировал сообщения, которые в свою очередь генерируют события.
UA6527P

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 26.11.2015 (Чт) 12:30

The trick писал(а):каким образом ты хочешь делать уведомления

Потому что затрудняюсь ответить на данный вопрос Изображение
Может "плюнуть на все" и довольствоваться SetTimer?
Интересно только, почему у него точность недостаточная. Может, там какие-то лишние действия есть, как например, в DoEvents?

Адская_Капча писал(а):Все равно вылетает... И при WT_EXECUTEINPERSISTENTTHREAD тоже

При этом память не может быть read (было write). Зачем тогда вообще существует этот QueueTimer...

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 26.11.2015 (Чт) 12:40

Адская_Капча писал(а):Ассемблерные вставки формирую во время процедуры инициализации (самая первая выполняющаяся в программе процедура), сохраняя в массив указатели на них, а уж потом их использую. Разве нельзя сделать по аналогии?


Какой смысл патчить уже готовую DLL на лету, добавляя туда нужную функцию, если кроме твоей программы никто не в курсе об этой функции и не сможет ей пользоваться. Да и твоя программа — только через вызов по указателю. Ну тогда вместо того, что писать генератор ассемблерной вставки, напиши обычную функцию в рамках своего проекта, которая сделает всё то же, что должна делать генерируемая ассемблерная вставка. То есть, если ты такой крутой, что можешь с помощью одного лишь пинцета построить и собрать станок по наливанию воды в пластиковые стаканчики, не проще ли просто самому взять и налить воду в пластиковый стаканчик?

Адская_Капча писал(а):А она, значит, должна появляться непременно посредством вызова из DLL? Я к тому, чтобы не делать свою DLL, а просто воспользоваться сишным рантаймом, а в самой программе уже "доделать" всё недостающее.

Она должна появиться — это главное. И только рантайм знает, как её правильно заполнять. Альтернативно — человек, разобравшийся в устройстве рантайма, тоже может знать как её сформировать. А сишный рантайм не знает о ней ничего. Так что он тут никаким боком не сдался вообще.

Адская_Капча писал(а):А формирование и использование ассемблерных вставок к ним относится?

Ты вообще не понимаешь, о чём там шла речь. Там речь шла о некоей парадигме, что VB предлагает программисту безопасную песочницу для мунипулирования с данными. Где все проблемы превращаются в ошибки, которые можно обработать с помощью On Error Goto или On Error Resume. И что в номер программисту никогда не придётся иметь дело с крэшем, если только он не пользовался какими-то грязными трюками. Какими угодно, к многопоточности эта мысль вообще никак не относилась.

Адская_Капча писал(а):Разве еще есть кто-то, кто использует рантайм 5-й версии? А что касается 6-го - неужели они тоже встречаются разные и функции могут лежать в разных местах?

Их полно, и они отличаются не только расположением функций, но и тем, что в разных версиях в разные структуры были добавлены новые поля, поэтому все смещения всех полей в разных версиях рантайма тоже отличаются:
vb_rt_versions.png
vb_rt_versions.png (11.87 Кб) Просмотров: 11555


Хочу заметить, что это только промежуточные версии, которые удалось насобирать мне — и между этими билдами тоже были билды, и возможно они тоже были опубликованы и где-то у кого-то работают. Кстати, обращаюсь ко всем: если у вас есть рантаймы с версиями не из этого списка — отправляйте мне (любым способом свяжитесь со мной).

Адская_Капча писал(а):Можно ли к нему как-то подобраться или получить его в VB? Если не главного, то дополнительного потока. Может, тогда отпадает необходимость создавать таймеры?

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

Да будет тебе известно, что цикл сообщений, это цикл, который, если отбросить лишнее, «бесконечно» выполняет две функции:
Код: Выделить всё
Dim msg as STRUCT_MSG
Do While GetMessage(msg, 0, 0, 0) <> 0
    DispatchMessage msg
Loop


При этом каждый вызов GetMessage возвращает очередное сообщение из очереди сообщений, а каждый вызов DispatchMessage находит окно, которому предназначалось сообщение и вызывает WindowProc этого окна, передавая данные сообщения. При этом если сообщений в очереди нет, то функция GetMessage замораживает текущий поток до момента, когда хоть одно новое сообщение появится в очереди. Как появится — она его вернёт, и потом вернёт следующее (если к тому времени она там будет), и так она вернётся все сообщения, и как только их там снова не окажется, она снова заснёт до лучших времён. То есть она работает подобно Sleep (или, это будет куда лучшей аналогией, — подобно WaitForSingleObject, но есть подозрение, что ты не в курсе об этой функции и этом механизме), только вместо таймаута в секундах для пробуждения использует факт получения нового сообщения потоком.

Так что цикл прокачки сообщений не крутится постоянно, а крутится только пока есть сообщения для обработки. И поэтому в Windows будь у тебя хоть 250 процессов — у них 99 процентов времени их GUI-потоки тупо спят и вообще не выполняются, поэтому система обеспечивает нормальную скорость работы, и загрузка процессора, отображаемая в диспетчере задач — далека от 100%.

Так что идея отмерять какие-то интервалы в цикле прокачки сообщений — несостоятельна.

"Просабклассить hwnd" - разве это не попытка подобраться к циклу сообщений, или это вовсе не он?

Нет, это не попытка.

Адская_Капча писал(а):Мне еще нужно умудриться найти этот самый момент... А отладка P-кода и поиск чего-либо в нем - это просто кошмар на улице Вязов. Все-таки мне хотелось, чтобы таймер работал и в режиме IDE.

Вообще-то я говорил про отладку скомпилированного проекта, причём скомпилированного в Native-код, потому что целью отладки должно быть узнавание контекста, в котором вызывает callback-процедура системным механизмом. А для этого не важно, отлаживаем мы скомпилированный проект или среду разработчик — системный механизм работает и там и там одинаково.

Но если на секунду подумать об отладке P-кода, работающего в рамках IDE, то и тут нет ничего сложного и кошмарного. Пишешь в Immediate Pane примерно что-то вроде ? Hex(AddressOf MyTimerCallBack), получаешь в ответ адрес, подключаешься отладчиком к IDE, прокручиваешься до этого адреса и ставишь там брекпоинт. Всё.

Адская_Капча писал(а):Неименованные мьютексы?

Ты написал первое, что пришло в голову, или единственное, что знал? Причём тут мьютексы? Их задача — обеспечить, чтобы к некоему защищаемому ресурсу в любой момент времени только один объект мог получать доступ. Это просто одноместный семафор. Ну и к чему это тут?

Тебе нужно из дополнительного потока просигнализировать в главный поток, что момент «икс» настал. Использовать для этого можно Events или вообще флаговую переменную, работать с которой нужно будет Interlocked-функциями.


И всё равно, ты не определился. Чем у тебя занимается код в момент, когда его должно прервать срабатывание таймера? Как на уровне кода должно выглядеть это прерывание? А вместо этих важных моментах ты говоришь о каких-то ассемблерных вставках и сабклассинге. Совершенно мимо кассы.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 26.11.2015 (Чт) 12:48

Адская_Капча писал(а):Интересно только, почему у него точность недостаточная.

Потому что Windows — не система реального времени.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 26.11.2015 (Чт) 13:10

Хакер писал(а):собрать станок по наливанию воды в пластиковые стаканчики

Ну станок, допустим, будет быстрее, точнее и производительнее наливать воду...
Вот например, мне ведь удалось сделать функцию замены символов в этой теме: viewtopic.php?f=1&t=50816. И теперь использую именно ее.

Хакер писал(а):On Error

Вроде бы эта штука прилично замедляет выполнение программ?

Хакер писал(а):Interlocked-функциями

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

Хакер писал(а):А вместо этих важных моментах ты говоришь о каких-то ассемблерных вставках и сабклассинге. Совершенно мимо кассы.

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

Хакер писал(а):Потому что Windows — не система реального времени.

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

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 26.11.2015 (Чт) 14:23

Адская_Капча писал(а):Вроде бы эта штука прилично замедляет выполнение программ?

Нет.
Если нужно будет генерировать высокие частоты (для чего?), то можно воспользоваться высокочастотным таймером - я уже давал пример.
UA6527P

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 26.11.2015 (Чт) 16:43

The trick писал(а):Я уже делал класс ожидания с асинхронным уведомлением

Имелся ввиду этот класс (viewtopic.php?f=28&t=46826)?
Может быть, с ним что-то получится и вдруг заработает... Спасибо за пример, посмотрю.

Только вот, пока в раздумьях, какой лучше вариант использовать: от The trick или от GSerg?
Контрол, конечно, это "минус", хотя я класс попробую переделать в модуль... Не люблю классы.
The trick, ваш класс является минимально жизнеспособным, т.е. ничего там сократить и убрать нельзя?

В режиме IDE вот что проявляется у меня - в процедуре CreateAsm на строке
hLib = GetModuleHandle(StrPtr("msvbvm60"))
hLib не создается, соответственно, равнение нулю и делается выход из функции. Странно как-то...

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 26.11.2015 (Чт) 17:04

Боже мой...
Изображение
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 26.11.2015 (Чт) 17:13

Хакер, я что-то делаю не так?
У меня склонность такая - все вылизывать и оптимизировать по отношению к коду.
По поводу моей функции (viewtopic.php?f=1&t=50816) - сейчас она у меня работает в режиме модуля а не класса, пришлось переделывать.

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

Пример The trick еще не был тронут, однако hLib не создается...

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 26.11.2015 (Чт) 17:14

Адская_Капча писал(а):he trick, ваш класс является минимально жизнеспособным, т.е. ничего там сократить и убрать нельзя?

Ну там опционально проверка в IDE ли мы, может что-то еще.
Ты в принципе сможешь сам сделать любой waiter. Мой работает следующим образом:
Создается класс окон с процедурой обработки сообщений в ассемблерной вставке - если ты будешь делать в модуле, то можно сделать и в обычной функции.
В классе окон имеется поле - общее количество окон этого класса, и адрес ассемблерной вставки (т.е. все классы используют одну и ту же вставку, даже если создать 100 экземпляров). Здесь уже код может выполнятся в другом потоке, точнее часть кода выолняется в другом поток - та которая ждет, а обработчик в потоке проекта.
Когда ты вызываешь асинхронное ожидание, это создает новый поток в ассемблерной вставке который ждет посредством одной из Wait* функций, когда функция отрабатывает она передает через PostMessage сообщение нашему окну, которое нпринадлежит потоку проекта, а сам поток завершается. В свою очередь окно в потоке проекта получая сообщение (когда очередная итерация цикла обработки сообщений извлекает его из очереди), запускает код генерации события через __vbaRaiseEvent.
Адская_Капча писал(а):hLib не создается, соответственно, равнение нулю и делается выход из функции.

Это не создание, а извлечение базового адреса msvbvm60, если он не извлекается значит эта библиотека не загружена.
UA6527P

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 26.11.2015 (Чт) 17:16

Адская_Капча писал(а):Хакер, я что-то делаю не так?

Пишешь полную ахинею. Такое впечатление, что ты вообще не понимаешь, что тебе пишут, и существуешь в каком-то параллельном мире.
Я не знаю, что делать.

Возможно ты троллишь и пытаешься, демонстрируя завидную непроходимость, спровоцировать какого-то изойти на повторяющиеся объяснения прописаных истин.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 26.11.2015 (Чт) 17:29

Хакер писал(а):существуешь в каком-то параллельном мире.

Возможно.

Я не всегда могу въехать с 1 раза, особенно если пост большой и сложный.

Хакер писал(а):Ответ абсолютно не в тему. Перечитай вопрос и попытайся понять его истинный смысл.

Я действительно сейчас не знаю, что мне ответить на данный вопрос.

Хакер писал(а):завидную непроходимость

Мне еще не доводилось всерьзез иметь дело с теорией и практикой многопоточности. У меня есть навыки программирования, но не во всех областях...

Хакер писал(а):спровоцировать какого-то изойти на повторяющиеся объяснения прописаных истин.

Зачем мне это нужно?
Вот что мне делать сейчас, не знаю... Или в отладчике пытаться выявить, из какого потока там приходят сообщения, или примеры The trick с GSerg анализировать...

А по каким мне еще критериям оценивать, хороший пример или плохой? Первое, что пришло мне в голову - это контрол, класс или модуль.

The trick писал(а):Это не создание, а извлечение базового адреса msvbvm60

Да, это верно. Однако осознание того, что моя фраза была написана неправильно, пришло уже после того, как эта фраза была написана и оговорена. Да, это не создание а извлечение. Что вижу, то и пытаюсь объяснить, особо не задумываясь.
Можно ведь не обращать внимание на мои неточности в выражении мыслей.

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

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 29.11.2015 (Вс) 19:53

Хакер писал(а):Пишешь в Immediate Pane примерно что-то вроде ? Hex(AddressOf MyTimerCallBack), получаешь в ответ адрес, подключаешься отладчиком к IDE, прокручиваешься до этого адреса и ставишь там брекпоинт. Всё.


1. Пишу в Form_Load кода, приведенного в начале темы, следующее:
Debug.Print Hex(AddressOf TimerCallBack)
2. Запускаю программу, выводит адрес: EC0AA4
3. В OllyDbg делаю: File > Attach выбираю Vb6.exe
4. В окне в заголовком CPU - thread 2. (00001414), module ntdll
правой кнопкой мыши выбираю Search For > Binary String > ввожу эти EC0AA4, но ничего не находит, ни в направлении Forward, ни в направлении Backward ((
Понятно, что в ntdll этого адреса быть не может, а где его тогда искать? В каком месте в среде IDE (а не в exe-файле) этот адрес может храниться? Нету нигде, похоже...
Не совсем ясно, что значит
Хакер писал(а):прокручиваешься до этого адреса


Предупреждаю, навыки с OllyDbg у меня маленькие, только для контроля работы ассемблерных вставок приходилось использовать, и то удавалось находить нужные места "с горем пополам". Мне небыло известно, что в OllyDbg можно аттачиться к процессам. Доселе приходилось компилировать в исполняемый файл и открывать его...

Как предполагается использовать таймера: это может быть, например, обновление полосы прогрессбара по расписанию (прогрессбар при этом сделан с помощью простой метки Label), или скачивание какого-то списка файлов из сети (скачивание начинается через определенные промежутки времени, а не одновременно все), либо имитация работы обыкновенных часов (в прямом смысле слова) на форме. Может быть и какое-то другое применение. Ну, например, еще может быть прерывание какого-то длительного действия (таймер меняет глобальную переменную, а ее проверка происходит в цикле длительного действия; вызов какого-то API или иной команды, прерывающих выполнение чего-либо).

The trick писал(а):извлечение базового адреса msvbvm60, если он не извлекается значит эта библиотека не загружена.

Очень странно, что у меня в одной сборке IDE эта библиотека оказывается не загружена (как тогда само IDE работает Изображение), а в другой IDE hLib-у присваивается число...

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 29.11.2015 (Вс) 21:44

Адская_Капча писал(а):правой кнопкой мыши выбираю Search For > Binary String > ввожу эти EC0AA4, но ничего не находит, ни в направлении Forward, ни в направлении Backward ((

В этом месте началась полная дурь.

Ты хоть понимаешь, что ты делаешь?
Тебе нужно перейти по адресу 00EC0AA4, а не искать байты EC 0A A4 внутри ntdll. Их там нет. Даже сам адрес 00EC0AA4 будет представлен в памяти как байты A4 0A EC 00, о чём я уже тебе говорил, но как об стену горох.

Тебе нужно не искать Binary String, а перейти по адресу.

Для этого надо в контекстном меню было жать не Search for...Binary String, а двумя пунктами выше Go toExpression или нажать Ctrl+G и ввести адрес.

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

А ещё лучше установить плагин CommandBar (без которого жизнь в OllyDbg не мила), и написать в нём команду at 0EC0AA4
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 01.12.2015 (Вт) 16:24

Хакер писал(а):Ты хоть понимаешь, что ты делаешь?

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

Хакер писал(а):будет представлен в памяти как байты

Да я знаю про big- и little- endian-ы...
Оказывается, есть волшебная команда BSWAP, которая, как оказалось, работает в 10 раз быстрее, чем всякие там умножения и деления Изображение. Если бы о ней было известно раньше... не пришлось бы городить огород из умножений или всяких там ntohl-ов и htonl-ов.

Хакер писал(а):Тебе нужно не искать Binary String, а перейти по адресу.

Это потому что было предположение, что можно найти в Binary String, т.е. где-то должна быть команда вызова этого адреса в бинарном виде в самом коде...

Итак,

при использовании флага &H20 (WT_EXECUTEINTIMERTHREAD):
всего 8 потоков, но наблюдалась ситуация, когда их всего 5 было. Видимо, по-всякому происходит... При останове на том адресе (00EC0AA4) в окошечке CPU написано, что это 7 поток (000016B0), см. рисунок 1 Изображение
Далее, нажимая клавишу F9 - вскоре 4 поток завершится с исключением (рисунок 2).

При использовании флага &H0 (WT_EXECUTEDEFAULT):
наблюдается всего 8 потоков, но была ситуация и с 9-ю. При останове на том адресе (00EC0AA4) в окошечке CPU написано, что это 8 поток (0000114C), см. рисунок 3, однако если понажимать F9, вскоре появится дополнительный, 9 поточек (или 10-й в другой раз), см. рисунок 4... И они чередуются попеременно еще, вот что удивительно... А потом 9-й крашится при чтении 001B0000 (рисунок 5).

Скрины.rar
(55.47 Кб) Скачиваний: 186

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 04.12.2015 (Пт) 9:00

Видимо, сделаю выбор в пользу примера The Trick, а не GSerg:
- для контрола нужна форма;
- у GSerg-а ANSI-варианты функций, а у The Trick юникодные;
- и у GSerg, похоже, отсутствуют проверки для IDE.

Судя по всему, нельзя без класса обойтись, так как тут используется механизм RaiseEvent Изображение.
И я не очень представляю, как здесь можно сделать замену на InterLocked-функции.
Поэтому, скорее всего, придется использовать этот RaiseEvent (к этому вопросу:
The Trick писал(а):Ты так и не сказал каким образом ты хочешь делать уведомления.
).
Хочется, конечно, сделать как-то через InterLocked, ведь Хакер сказал, что это более производительно, но как - не знаю...

Но создание ассемблерной вставки все-таки попробую перенести в модуль, ведь модули работают быстрее классов.

Такой вопрос возник - как устроена функция WaitForSingleObject изнутри?
Наверняка, там внутри должен быть какой-то цикл, в котором проверяется время, и если оно истекло - происходит отработка. Если там есть цикл с проверкой времени, может, проще его реализовать на ассемблере (для повышения быстродействия, естественно), как-то запуская его в другом потоке?
Оказывается, WaitForSingleObject - это обертка для WaitForSingleObjectEx, который вызывает NtWaitForSingleObject, а последний вызывает KiFastSystemCall, который вызывает SYSENTER, но это не цикл... А дальше нельзя ничего увидеть. Так-то интересно и увлекательно узнавать, что это всего-лишь обертка Изображение

The trick, а чем в Вашем примере обусловлена необходимость в использовании функций SafeArrayAllocDescriptor и SafeArrayDestroyDescriptor (вместо простого Redim) в процедуре CreateAsm? Так будет быстрее работать?
Если да, то больше не буду использовать простой Redim...

Чем в структурах SThreadArg и MThreadArg обусловлен выбор типа переменных pHandle и pResult как Variant, а не Long? Variant ведь это более медленный тип. Или это для чего-то необходимо?

Оказывается, существует еще какая-то функция RegisterWaitForSingleObject, вот только стоит с ней связываться или нет?

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

А каким образом нужно переделывать код в данном случае и как это лучше сделать оптимальнее?
Ассемблерную вставку править или просто зациклить создание новых ожиданий, каждый раз используя функции SetWaitableTimer и tmr.vbWaitForSingleObject? Или в самом классе что-то подправить?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 04.12.2015 (Пт) 9:46

Адская_Капча писал(а):Наверняка, там внутри должен быть какой-то цикл, в котором проверяется время, и если оно истекло - происходит отработка.

У тебя совершенно неверное представление об устройстве вещей. Никакого цикла, о котором ты думаешь, там нет (даже если если у тебя была бы возможность заглянуть дальше SYSENTER). И никакой проверки времени там тоже нет.

Там объект помещается в список ожидаемых объектов текущего потока, опционально создаётся ядерный таймер на случай (если указан интервал для WaitForSingleObject), а потом поток маркируется как «ожидающий» и происходит насильное переключение контекста на другой поток. Больше процессор вообще не будет переключаться на текущий поток, пока либо ожидаемый объект не перейдёт в signaled-состояние, либо не истечёт служебный таймер, либо не придёт APC.

На случай APC все вышеописанные действия засунуты в бесконечный цикл, но этот не тот цикл, о котором ты думал, и вообще он тебя не касается, потому что ты использует WaitForSingleObject, а не WaitForSingleObjectEx.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 04.12.2015 (Пт) 10:03

Хакер писал(а):если указан интервал для WaitForSingleObject

Я как раз про этот случай, когда создается ядерный таймер при указывании интервала. Как этот ядерный таймер внутри работает и есть ли в нем цикл с проверкой времени в конечном итоге?

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

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Queue-таймер вылетает...

Сообщение Хакер » 04.12.2015 (Пт) 10:31

Адская_Капча писал(а):Я как раз про этот случай, когда создается ядерный таймер при указывании интервала. Как этот ядерный таймер внутри работает и есть ли в нем цикл с проверкой времени в конечном итоге?

Нету.

Адская_Капча писал(а):Дело в том, что переключение в режим ядра требует немало вычислительных ресурсов... Вот и появилась идея - если как-то это в юзермодном режиме реализовать?

Спин-блокировку? Чтобы поток загрузил ядро на сто процентов, а потом всё равно произошло бы переключение на другой поток? А после того, как твоему потоку вновь выпадет шанс выполнить, будет уже большое опоздание?

Ты не понимаешь, чего хочешь, и хочешь непонятно чего.

Как бы там ни было, решение проблем со time-critical приложениями состоит в том, чтобы:
  • Установить потоку высокий приоритет.
  • Вместо того, чтобы писать код, который через 20 микросекунд должен нарисовать летящую в центре экрана муху, писать его так, чтобы в нужный момент времени он с большой точностью вычислил, где должна быть нарисована муха, и рисовал её там, где нужно.
  • Использовать предоставляемые системой сервисы.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Адская_Капча
Обычный пользователь
Обычный пользователь
Аватара пользователя
 
Сообщения: 60
Зарегистрирован: 28.07.2014 (Пн) 20:22

Re: Queue-таймер вылетает...

Сообщение Адская_Капча » 04.12.2015 (Пт) 12:50

Хакер писал(а):Ты не понимаешь, чего хочешь, и хочешь непонятно чего.

Наверное, Вы правы...
Мне просто хочется сделать самый лучший и идеальный таймер, чтобы быстродействие и точность было супер и размер кода не был при этом огромный, подобно простыне.
Только вот в сфере многопоточности я не бум-бум!
Столько всего - спин-блокировки всякие, InterLocked, потоки, APC, а также RegisterWaitForSingleObject и куча других недавно узнанных фуцнкций, помимо CreateTimerQueueTimer (вон их сколько всяких - https://msdn.microsoft.com/ru-ru/librar ... 60(v=vs.85).aspx, да и английский еще)...
Даже и не знаешь, за что взяться и по какому пути пойти...
Надо ведь тоже попробовать представить себя на моем месте.
Может плюнуть на все?

The trick
Постоялец
Постоялец
 
Сообщения: 781
Зарегистрирован: 26.06.2010 (Сб) 23:08

Re: Queue-таймер вылетает...

Сообщение The trick » 04.12.2015 (Пт) 13:59

Адская_Капча писал(а):Судя по всему, нельзя без класса обойтись, так как тут используется механизм RaiseEvent Изображение.

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

При чем вообще Interlocked-функции?
Адская_Капча писал(а):Хочется, конечно, сделать как-то через InterLocked, ведь Хакер сказал, что это более производительно, но как - не знаю...

Тебе придется постоянно опрашивать состояние в цикле. С таким же успехом можно и высокочастотный таймер заюзать без всяких синхронизаций.
Адская_Капча писал(а):Но создание ассемблерной вставки все-таки попробую перенести в модуль, ведь модули работают быстрее классов.

Не правда, точнее это настолько незначительно, что этим можно пренебречь.
Адская_Капча писал(а):The trick, а чем в Вашем примере обусловлена необходимость в использовании функций SafeArrayAllocDescriptor и SafeArrayDestroyDescriptor (вместо простого Redim) в процедуре CreateAsm? Так будет быстрее работать?
Если да, то больше не буду использовать простой Redim...

Нет, это для того чтобы замапить массив на RWE память. ПРосто если сделать Redim, то он выделит память под данные, а мне не нужно их выделять т.к. они были выделены до этого.
Адская_Капча писал(а):Чем в структурах SThreadArg и MThreadArg обусловлен выбор типа переменных pHandle и pResult как Variant, а не Long? Variant ведь это более медленный тип. Или это для чего-то необходимо?

Т.е. __vbaRaiseEvent принимает Variant аргументы.
Адская_Капча писал(а):А каким образом нужно переделывать код в данном случае и как это лучше сделать оптимальнее?
Ассемблерную вставку править или просто зациклить создание новых ожиданий, каждый раз используя функции SetWaitableTimer и tmr.vbWaitForSingleObject? Или в самом классе что-то подправить?

Ассемблерную вставку править. В моем случае поток уничтожается после окончания ожидания, для таймера целесообразней сделать периодическое ожидание. В моем случае большое количество времени будет уходить на создание/уничтожение потока.
UA6527P

След.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Google-бот, Yandex-бот и гости: 20

    TopList