О таймерах

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

О таймерах

Сообщение Адская_Капча » 09.08.2014 (Сб) 20:06

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

Вопрос 1) - встроенный таймер, который в палитре стандартных контролов - хорошо его использовать или нет? Использует ли он DoEvents?

Использование связки Sleep + Doevents в цикле (или заменяя Doevents на PeekMessage + TranslateMessage + DispatchMessage) имеет недостаток - если схватить мышью форму за заголовок - таймер приостановится. На этом форуме Хакер в писал (viewtopic.php?f=1&t=37142), что эту задачу нельзя решить в общем случае. По поводу фиберов - есть статья tyomitch-а, однако ссылки на примеры мертвые...

Можно попробовать использовать потоки, но они работают только в скомпилированном виде и использование очень ограничено. Хочу в цикле потока работать с формой (в качестве примера - что-то напечатать на форме или сменить заголовок) - переделанный пример от Кривоус Анатолия не работает корректно (зависает при попытке выгрузить все потоки процедурой UnloadAll), потому что я могу чего-то не знать. И API в цикле потока просто так нельзя использовать, приходится юзать TLB.

Вопрос 2) - что у меня не правильно в переделанном примере многопоточности от Кривоус Анатолия?

Код формы (на форме 2 кнопки cmdNewThread и cmdUnload):

Код: Выделить всё
Option Explicit

' Пример многопоточности VB6
' © Кривоус Анатолий Анатольевич (The trick), 2013
' Работает только в скомпилированном виде

Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadId As Long) As Long
Private Declare Function SetThreadPriority Lib "kernel32" (ByVal hThread As Long, ByVal nPriority As Long) As Long
Private Declare Function GetThreadPriority Lib "kernel32" (ByVal hThread As Long) As Long
Private Declare Function GetExitCodeThread Lib "kernel32" (ByVal hThread As Long, lpExitCode As Long) As Long

'Private Const DC_PEN As Long = 19
Private Const INFINITE = &HFFFFFFFF
Private Const MAX = 255

Dim Threads As Collection
Dim Thread(MAX - 1) As Point

Private Sub cmdNewThread_Click()
    Dim hThread As Long, IDThread As Long, Pt As Point

    Pt.Status = True
   
    Thread(Threads.Count) = Pt
    hThread = CreateThread(ByVal 0, 0, AddressOf MoveProc, Thread(Threads.Count), 0, IDThread)
    If hThread Then Threads.Add hThread Else MsgBox ("Неудалось создать поток"): Exit Sub
    SetThreadPriority hThread, 0
    Print hThread & " " & IDThread
    cmdNewThread.Enabled = False
End Sub

Private Sub cmdUnload_Click()
   UnloadAll
End Sub

Private Sub Form_Load()
    Set Threads = New Collection
End Sub
Private Sub UnloadAll()
    Dim i As Variant, l As Long
    For Each i In Threads
        Thread(l).Status = False
       
        Dim Ret As Long
        GetExitCodeThread CLng(i), Ret
        If Ret = &H103& Then
            WaitForSingleObject CLng(i), INFINITE
        End If

        'WaitForSingleObject CLng(i), INFINITE
        Print CLng(i)
        l = l + 1
    Next
End Sub
Private Sub Form_Unload(Cancel As Integer)
    UnloadAll
End Sub


Код модуля:

Код: Выделить всё
Option Explicit

' Пример многопоточности VB6
' © Кривоус Анатолий Анатольевич (The trick), 2013
' Работает только в скомпилированном виде

Public Type Vector
    X As Double
    Y As Double
End Type
Public Type Point
    Pos As Vector
    Spd1 As Single
    Spd2 As Single
    Color As Long
    Status As Boolean
End Type

Public Play As Boolean

Private Const Pi2 = 6.28318530717959

'Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Function MoveProc(Pt As Point) As Long
    Dim Ph1 As Single, Ph2 As Single, Scl As Single
   
    Do
        Ph1 = Ph1 + Pt.Spd1: Ph2 = Ph2 + Pt.Spd2
        If Ph1 > Pi2 Then Ph1 = Ph1 - Pi2
        If Ph2 > Pi2 Then Ph2 = Ph2 - Pi2
        Scl = Sin(Ph2)
       
       
        Pt.Pos.X = Cos(Ph1) * Scl * 100 + 100
        Pt.Pos.Y = Sin(Ph1) * Scl * 100 + 100
       
        'Sleep 500
        abc1 CStr(Pt.Pos.Y) 'frmTest.Caption = CStr(Scl)

        ' Т.к. VB анализирует код, то в VB "думает" что
        ' никто не может обратится к локальной переменной этой процедуры извне
        ' в реальности к элементам массива Thread, модуля frmTest.
        ' Поэтому если не обрабатывать переменную Pt.Status, то VB "решит" (если стоит оптимизации кода)
        ' что значение ее всегда равно в теле цикла, и проверит значение до цикла
        ' Получится что цикл будет крутиться бесконечно.
        ' Чтобы такого не было вставляем вот эту строчку
        Pt.Status = Not Not Pt.Status
       
    Loop While Pt.Status
End Function

Public Sub abc1(f As String)
    'frmTest.Print f 'Caption = f
    frmTest.Caption = f
End Sub


Есть еще вариант использовать API SetTimer/KillTimer, либо CreateTimerQueueTimer. Они работают нормально, то есть если схватить форму, таймер будет продолжать работать.

Вопрос 3) - SetTimer как работает изнутри? Он лучше чем стандартный контрол таймера VB в плане производительности и "тяжелизны"? И там нету никакого Doevents?
Вопрос 4) - Верно ли, что CreateTimerQueueTimer еще лучше использовать, чем SetTimer? SetTimer - обертка ли над CreateTimerQueueTimer?
Вопрос 5) - есть ли что-то, что еще "ниже" чем CreateTimerQueueTimer?
Вопрос 6) - как можно на лету поменять интервал таймера при использовании CreateTimerQueueTimer, не прибегая к уничтожению и тут же созданию нового? Примеров на эту тему практически нет.

Спасибо за внимание к моему вопросу.

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

Re: О таймерах

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

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

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

Адская_Капча писал(а):Использует ли он DoEvents?

Как это понять? DoEvents это просто функция, которая лезет и достаёт новое из очереди сообщений текущего потока. Как таймер может использовать эту функцию? Зачем ему она?

Адская_Капча писал(а):Использование связки Sleep + Doevents в цикле (или заменяя Doevents на PeekMessage + TranslateMessage + DispatchMessage) имеет недостаток - если схватить мышью форму за заголовок - таймер приостановится.

Вообще говоря, Peek+Translate+Dispatch лучше, чем DoEvents, потому что DoEvents делает помимо этого ещё очень много всего.

Не возьмусь сейчас опять писать, что именно, просто нашёл свой пост ссылками на возможные объяснения:
Я в этом посте писал(а):Ну а насчёт того, что DoEvents в подобных циклах, это настоящее зло, можешь почитать тут:
1) viewtopic.php?f=1&t=41820
2) viewtopic.php?f=1&t=40185
3) Ещё что-то тут http://forum.sources.ru/index.php?showt ... ew=showall — но по-моему только с отсылами на меня.


_______


Адская_Капча писал(а):На этом форуме Хакер в писал (viewtopic.php?f=1&t=37142), что эту задачу нельзя решить в общем случае. По поводу фиберов - есть статья tyomitch-а, однако ссылки на примеры мертвые..


Кстати, в том топике все мои картинки тоже мёртвые (их даже и не видно, но их там было много). Можно примеры мёртвых сслок примеров от tyomitch-а?

______

По поводу многопоточности Анатолия пусть ответит Анатолий, но вообще-то моя позиция состоит в том, что есть только две пригодные для использования формы многопоточности:
  1. Штатная многопоточность VB, которая вступает в игру в ActiveX-EXE-проектах (режим Thread per Object).
  2. Моя многопоточность, которую я так и не могу найти время доделать. Её степень готовности, если сравнивать с автомобилем: машина ездит, но стёкол нет.
Другие способы достижения многопоточности я считаю несостоятельными и даже если там что-то получается, то это хождение по острию ножа.

Адская_Капча писал(а):Вопрос 3) - SetTimer как работает изнутри?

Пытался найти свой большой пост про устройство SetTimer и поток RIT, но не смог найти вообще. Или пост пропал, или мне приснилось, что я его писал. В общем, это длинная песня.

Задай более конкретизированный вопрос.

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

Он не лучше и не хуже. Потому что он не отличается от таймера VB, а он лежит в основе таймера VB.
VB-таймер-контрол использует API функцию SetTimer для своей работы. Со своей стороны VB-рантайм обрабатывает сообщение WM_TIMER, находит COM-объект таймера, к которому относится сообщение, и инициирует на этом объекте событие «Timer», которые подписчики могут обработать.

Адская_Капча писал(а):И там нету никакого Doevents?

Как уже было выше сказано, это странная и непонятная постановка вопроса. Ни Win32API-таймер, ни VB-таймер не имеют никакого прямого отношения к DoEvents.

Адская_Капча писал(а):Вопрос 4) - Верно ли, что CreateTimerQueueTimer еще лучше использовать, чем SetTimer? SetTimer - обертка ли над CreateTimerQueueTimer?

Какой лучше — зависит от обстоятельств. Это два сильно разных механизма, и SetTimer не является обёрткой над CreateTimerQueueTimer.

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

ChangeTimerQueueTimer
—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: О таймерах

Сообщение Адская_Капча » 10.08.2014 (Вс) 10:51

Хакер писал(а):Это некорректный вопрос. У каждой вещи есть область и граница применения.

Хорошо, попробую тогда выразиться более понятно.
Требуется в бесконечном цикле выполнять определенные действия (в качестве абстрактного примера - смена заголовка кнопки или формы на рандомное число) с формой с заданной периодичностью (например 1 секунда). Со временем, начнется отставание таймера от реального времени. Так было замечено со Sleep + Doevents. Тем более, что действия с формой все равно отнимают какое-то количество времени. Для этого, собственно, и нужна корректировка (1000 - wMilliseconds) путем изменения интервала таймера (приходится получать текущее время для этого в структуре SYSTEMTIME).

Встроенный таймер - может ли обеспечить бесконечный цикл?
Встроенный таймер - правильно понимаю, что он имеет более плохую точность по сравнению с SetTimer/CreateTimerQueueTimer?

Хакер писал(а):Как таймер может использовать эту функцию? Зачем ему она?

Потому что мне казалось (думая одновременно об API Sleep), что если форма не зависает то это так. Peek+Translate+Dispatch он, значит, тоже не использует?
Встроенный таймер использует отдельный поток (раз при захвате формы мышью ничего не приостанавливается) или это мое заблуждение?

Хакер писал(а):Не возьмусь сейчас опять писать

Не заставляю, так как ценю чужое время, поэтому могу довольствоваться просто краткими ответами. Какие-то ссылки про Doevents есть - ну и достаточно.

Хакер писал(а):Можно примеры мёртвых сслок примеров от tyomitch-а?

Та самая статья: http://www.vbstreets.ru/VB/Articles/66058.aspx
Чуть ниже архив с примерами (который у меня не скачивается): http://vbstreets.ru/Stuff/Downloads_Get ... x?id=66059

Хакер писал(а):я так и не могу найти время доделать.
это хождение по острию ножа.

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

Хакер писал(а):Потому что он не отличается от таймера VB, а он лежит в основе таймера VB.
VB-таймер-контрол использует API функцию SetTimer для своей работы

На 100% одинаково? Ведь контрол, в отличие от просто API - это дополнительный визуальный интерфейс и нагрузка?
Как тогда происходит смена интервала VB-таймера? Просто повторно вызывается API SetTimer с параметром nIDEvent и новым uElapse, как описано здесь (http://www.vsokovikov.narod.ru/New_MSDN ... ttimer.htm)?

Хакер писал(а):Какой лучше — зависит от обстоятельств.

1 - в плане точности.
Здесь (http://omeg.pl/blog/2011/11/on-winapi-t ... esolution/) написано, что точность CreateTimerQueueTimer лучше, чем SetTimer. Пока поверю статье, на 90%. Насчет timeSetEvent незнаю, потому что здесь (http://msdn.microsoft.com/en-us/library ... 34(v=vs.85).aspx) написано, что timeSetEvent устарела. Кроме того, Winmm.dll может и отсутствовать на каком либо компьютере, а Kernel32 есть всегда.
2 - в плане производительности кода и тяжелизны (по аналогии: Peek+Translate+Dispatch лучше чем Doevents, а вот CreateTimerQueueTimer лучше ли, чем SetTimer? И timeSetEvent лучше ли чем CreateTimerQueueTimer?).

Вот и думаю, какой таймер оптимальнее и лучше всего использовать... Вы бы сами какой вариант использовали?
И существуют ли еще какие-либо Callback-таймера?

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

Хакер, супер! На радостях пойду плясать.

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

Re: О таймерах

Сообщение Хакер » 10.08.2014 (Вс) 11:56

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

Это в общем случае не очень правильный подход, потому что это не соответствует event-driven-парадигме. Бесконечный цикл и так уже есть — спрятанный от тебя бесконечный цикл, который в нужные моменты вызывает нужные обработчики нужных событий. Какой смысл делать свой собственный бесконечный цикл?

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

Потому что интервал таймера — это не время между двумя срабатываниями. Это не время между началом работы обработчика предыдущего тика и началом работы обработчика текущего тика. Это разница времени между концом работы обработчика предыдущего тика и началом работы обработчика следующего.

Более того: это минимальная разница. Тебе гарантируют, что таймер будет вызван не раньше, чем через время t. Но он может быть вызван через любое время, большее, чем t.

Более того: Windows вообще по своей природе и архитектуре не является ОСРВ. Поэтому, как не извращайся, гарантии того, что всё произойдёт вовремя, всё равно никогда не будет.

Адская_Капча писал(а):Тем более, что действия с формой все равно отнимают какое-то количество времени. Для этого, собственно, и нужна корректировка (1000 - wMilliseconds) путем изменения интервала таймера (приходится получать текущее время для этого в структуре SYSTEMTIME).

Потому что нужно использовать подход с schedule next action at XXX, а не sleep for YYY.

Адская_Капча писал(а):Встроенный таймер - может ли обеспечить бесконечный цикл?

Бессмысленный вопрос.

Адская_Капча писал(а):Встроенный таймер - правильно понимаю, что он имеет более плохую точность по сравнению с SetTimer/CreateTimerQueueTimer?

Правильно ли я понимаю, что автомобиль менее надёжен, чем стальной шарик?

Кстати: здесь «встроенный таймер» противопоставляется функции SetTimer, значит под встроенным имеется VB-таймер.


Адская_Капча писал(а):Потому что мне казалось (думая одновременно об API Sleep), что если форма не зависает то это так. Peek+Translate+Dispatch он, значит, тоже не использует?

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

Штатно любая GUI-программа Windows в потоке, который владеет окнами, крутит message loop — цикл прокачки оконных сообщений. Сишники этот цикл пишут сами, вручную, и он часть их кода. VB-программисты не задумываются о нём, потому что цикл является частью рантайма.

И там не PeekMessage, а GetMessage. Да дальше Translate-ы и в конце Dispatch.

Этот цикл «крутится» сам по себе. До существования таймера крутится. При создании таймера — крутится. При активации таймера — крутится. После срабатывания таймера — крутится. После уничтожения таймера — крутится.
Этот цикл вообще ничего не знает о таймере и не задумывается о таймерах.
А таймер ничего не знает о конкретном цикле и не задумывается о нём.

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

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

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

Кстати: а здесь под «встроенными таймерами» уже видимо имеется в виду WinAPI-таймер, раз говорится про «при захвате». Путаница. Разберись с терминологией свой собственной.

Но вообще, ни VB-таймер ни WinAPI-таймер не создают и не используют никаких доп. потоков внутри твоего процесса.
Тем не менее, WinAPI-таймер использует RIT-поток (который и рассылает всем прочим потоком сообщение WM_TIMER), а VB-таймер в свою очередь использует WinAPI-таймер. Но это не то, о чём ты спрашиваешь.

К тому же, непонятна логика: какая связь между тем, продолжает ли обработчик вызываться при перетаскивании или не продолжает, и тем, есть ли дополнительный поток. Связи — никакой.

Адская_Капча писал(а):Та самая статья: http://www.vbstreets.ru/VB/Articles/66058.aspx
Чуть ниже архив с примерами (который у меня не скачивается): http://vbstreets.ru/Stuff/Downloads_Get ... x?id=66059

Это можно (и нужно) починить. Я добавлю это в список своих задач.

Адская_Капча писал(а):На 100% одинаково? Ведь контрол, в отличие от просто API - это дополнительный визуальный интерфейс и нагрузка?
Как тогда происходит смена интервала VB-таймера?

Я не говорю, что они на сто процентов одинаковы. Да и здравый смысл должен говорить тебе, что это было бы бессмысленное утверждение. Я говорю о том, что VB-таймер и WinAPI-таймер основываются не на разных механизме, а один на другом.

Контрол — это не визуальный интерфейс. Это ООП-обёртка над WinAPI-таймером. С одной стороны обращения к объекту-контролу транслируются в вызовы WinAPI-функций. С другой стороны: приходящие в очередь сообщения WM_TIMER транслируются в обход всех подписчиков событий и вызов каждого обработчика по очереди.


Адская_Капча писал(а):Хакер, супер! На радостях пойду плясать.

Я надеюсь ты озаботился флагами? Чтобы у тебя callback не вызывался в первом попавшемся потоке из твоего процесса?
—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: О таймерах

Сообщение Адская_Капча » 10.08.2014 (Вс) 13:30

Хакер писал(а):Бесконечный цикл и так уже есть

Имеется ввиду само существование программы?

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

Уточню - чтобы начало действия с формой совпадало с интервалами системного времени (например: 12.02.05.000 - смена заголовка; 12.02.06.000 - смена заголовка; и т.д.).

Хакер писал(а):он может быть вызван через любое время, большее, чем t.

Собственно, для этого и нужна корректировка 1000 - wMilliseconds.

Хакер писал(а):Потому что нужно использовать подход с schedule next action at XXX

Я не знаю, каким образом, какими API реализуется этот подход, поэтому использую подход Sleep на (1000 - wMilliseconds).

Хакер писал(а):Правильно ли я понимаю, что автомобиль менее надёжен, чем стальной шарик?

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

Поэтому: возможно ли обойтись SetTimer/KillTimer, не используя VB-таймер, и будет ли это действительно более оптимальный код в плане быстродействия?

Хакер писал(а):Штатно любая GUI-программа Windows в потоке, который владеет окнами, крутит message loop — цикл прокачки оконных сообщений.

Это и имелось ввиду под "Бесконечный цикл и так уже есть"?

Хакер писал(а):И там не PeekMessage, а GetMessage

Что лучше использовать, PeekMessage или GetMessage?
Как-то попадался пример от Анатолия в сети, не помню где, но там используется именно PeekMessage. И вместо структуры просто массив Long.

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

Так как VB-таймер-контрол - это "автомобиль", а SetTimer - это "шарик", то переформулирую:
SetTimer использует ли отдельный поток? Видимо да, в отличие от метода "Sleep + Doevents", так как при захвате экземпляра формы происходит приостановка.

Хакер писал(а):Но это не то, о чём ты спрашиваешь.

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

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

Sleep + Doevents (aka Translate+Dispatch) не создает поток, поэтому при перетаскивании всё останавливается.
SetTimer/CreateTimerQueueTimer использует дополнительный поток, поэтому при перетаскивании всё продолжает работать.
Потому что захватывание работает именно с главным оконным потоком. Верно?

Адская_Капча писал(а):думая одновременно об API Sleep

Думая одновременно, параллельно об этом, наряду с VB-таймером-контролом, но не имея ввиду его самого (этого API Sleep).

Хакер писал(а):callback не вызывался в первом попавшемся потоке

Какими флагами? В MSDN о ChangeTimerQueueTimer по вышеприведенной ссылке ничего не говорится про флаги.
Или Вы имели ввиду CreateTimerQueueTimer? Делаю так:

Код: Выделить всё
CreateTimerQueueTimer hTimer, hQueue, AddressOf TimerCallBack, ByVal 0&, 0, 1000, 0

Да и насколько это важно?
А может

Изображение
?

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

Re: О таймерах

Сообщение The trick » 10.08.2014 (Вс) 16:21

Точного интервала времени в Windows тебе не получить. Можно максимально приблизится, но все-равно не получить, т.к. каждому потоку выделяется определенный квант времени. На высокочастотных таймерах можно прибавить точность, но так или иначе эти импульсы будут "грязные" из-за переключения потоков. Вот например пример генерации импульсов 2 кГц, но там же можешь почитать какие проблемы с этими импульсами возникают.
Насчет многопоточности.
Во-первых, поток должен быть проинициализирован если ты используешь COM, Declared API, потокозависимые функции рантайма. В том примере, где ты взял этот код, такие не используются, а ты использовал (frmTest.Caption).
Во-вторых, просто так нельзя передавать ссылку на объект между потоками (читай про маршаллинг).
Как-то попадался пример от Анатолия в сети, не помню где, но там используется именно PeekMessage. И вместо структуры просто массив Long.

Насчет DoEvents, вот я делал простейшую реализацию получения сообщений очереди. Массив - это структура MSG. Почему PeekMessage, потому что GetMessage - блокирующая, и если не будет сообщений в очереди, то поток будет простаивать в ожидании.
Можешь использовать SetTimer, при ресайзе и перемещении формы сообщения также будут поступать.
UA6527P

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

Re: О таймерах

Сообщение Адская_Капча » 10.08.2014 (Вс) 17:30

Значит, это и есть та самая
Хакер писал(а):Какой смысл делать свой собственный бесконечный цикл?

Хакер писал(а):Штатно любая GUI-программа Windows в потоке, который владеет окнами, крутит message loop — цикл прокачки оконных сообщений.

идея? Просто просабклассить hwnd экземпляра формы? И в процедуре сабклассинга получать время (QueryPerformanceCounter), и если оно достигнет секунды - выполнить изменение заголовка формы? Для этого нужно отслеживать какое-то особое сообщение WM_xxx, или не обязательно? И при захватывании мышью приостановки не будет?

Анатолий, и Вас также хочу поблагодарить! Русскую, народную плясать.

Только сходу не могу разобраться в Вашем классе clsTrickSubclass.cls (очень уж он сложный и навороченный), а я хочу понять как это все работает. Без ассемблерных вставок никак нельзя? Ведь сабклассить можно и проще, попадались примеры и попроще.

Первый вопрос возник - а почему именно HeapAlloc? Чем он лучше GlobalAlloc или VirtualAlloc? В плане быстродействия функции? Здесь (viewtopic.php?p=6770708#p6770708) у Вас тоже именно HeapAlloc. А Хакер где-то вообще использовал VirtualProtect.

Еще есть CreateWaitableTimer, но он остановится при захвате мышью...

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

Тогда буду делать черерз маршаллинг.

2Хакер,
Хочу выразить отдельную благодарность за функцию InterlockedExchangeAdd здесь (viewtopic.php?p=6740748#p6740748). Как Вы так знаете все API? Меня это поражает. А то сижу и не могу сделать так, чтобы раз - и все API знать.
Видимо, сложение в InterlockedExchangeAdd циклическое - если к &HFFFFFFFF прибавить 1, то будет снова 0, и так далее. И не нужно придумывать ничего с If Else.
Если заменить на InterlockedAdd, почему-то уже не будет складывать... Или там уже не kernel32? В MSDN ничего не сказано про конкретную dll.

А существует ли какая-либо малоизвестная API функция копирования байтов в прямом порядке, чтобы не прибегать к операциям \ и And? Copymemory копирует байты в обратном порядке.

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

Re: О таймерах

Сообщение Хакер » 10.08.2014 (Вс) 18:00

Адская_Капча писал(а):Видимо, сложение в InterlockedExchangeAdd циклическое - если к &HFFFFFFFF прибавить 1, то будет снова 0, и так далее.

Такое сложение не в InterlockedExchangeAdd, а в компьютере — вообще.

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

Вообще мимо классы. Я ничего такого не говорил и не намекал.

Адская_Капча писал(а):Первый вопрос возник - а почему именно HeapAlloc? Чем он лучше GlobalAlloc или VirtualAlloc?

У тебя каша в голове. GlobalAlloc — это функция времён компьютеров i286 и системы Windows 3.1.
Уже 20 лет назад в 32-битном мире она была оставлена исключительно из соображений совместимости (чтобы куча програмистов просто перекомпилировали свой код под 32-битные Windows, не переписывая сам код). И она является просто переходником к HeapAlloc.

Что же касается HeapAlloc/VirtualAlloc, то это функции совершенно разного уровня. Функции с префиксами Heap — для работы с кучами (куча — это такая фундаментальная структура данных). Они оперируют кучами и блоками произвольной байтовой длины и имеют под капотом некую стратегию выделения маленьких блоков из больших куч.
Функции с префиксом Virtual — функции для работы со страницами адресного пространства процесса. Они оперируют страницами (при выделении/освобождении/смене атрибутов) и блоками по 64 Кб (при резервировании/разрезервировании).

Адская_Капча писал(а):А Хакер где-то вообще использовал VirtualProtect.

Не для выделения памяти, а для смены атрибутов страницы. Опять ты всё мешаешь в кучу.

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

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

Адская_Капча писал(а):А существует ли какая-либо малоизвестная API функция копирования байтов в прямом порядке, чтобы не прибегать к операциям \ и And? Copymemory копирует байты в обратном порядке.

Опять какая-то глупость.
Во-первых, не копирует RtlMoveMemory в обратном порядке. Во-вторых, даже если бы копировала в обратном, какая разница — ведь копия получается идентична оригиналу.
И при чём тут And и \?

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

Читай:
https://ru.wikipedia.org/wiki/%CF%EE%F0 ... 9%F2%EE%E2

x86 использует little-endian.
—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: О таймерах

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

Я в курсе про little и big endian. Только есть конкретная задача: из набора идущих байтов, например "12 34 56 78" нужно сделать число, причем именно &H12345678, а не &H78563412. Приходится преобразовывать, а это лишние затраты на вычисления.

Хакер писал(а):Что же касается HeapAlloc/VirtualAlloc

Подразумевался вопрос - какой способ использовать предпочтительнее для ассемблерных вставок.

Хакер писал(а):Не надо.

Но у меня получилось! Зачем мне нужно знать и помнить абсолютно всё (что невозможно в принципе), и всю жизнь неотступно следовать установкам, а также всюду и везде оперировать идеальной терминологией? Иногда можно и поэкспериментировать, пожить против правил и перекрасить мир в свои цвета...

Работает нормально, в том числе и в IDE. The Trick помог!

VBStreets рулит!

Так что у Адской Капчи кашки поубавилось - удалось немного откушать. Не без TLS конечно Изображение

На радостях того, что удалось сделать поток как мне нужно - я временно улетаю... В параллельную реальность!
Может быть вернусь, всем спасибо и пока!

bye.png
bye.png (43.14 Кб) Просмотров: 3363

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

Re: О таймерах

Сообщение Хакер » 11.08.2014 (Пн) 14:27

Адская_Капча писал(а):Я в курсе про little и big endian. Только есть конкретная задача: из набора идущих байтов, например "12 34 56 78" нужно сделать число, причем именно &H12345678, а не &H78563412. Приходится преобразовывать, а это лишние затраты на вычисления.


Набор байт 12h 34h 56h 78h, хранящийся в памти x86-компьютера, означает число 0x78563412, а не 0x12345678. Поэтому все функции копирования, про которые ты говоришь, копируют правильно. Если твои байты приходят откуда-то, кто провозглагает, что они именно в big-endian-порядке, например приходят по сети по протоколу, который использует big endian, то для этого есть функциюя ntohl (network to host (long)).

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

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


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

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 53

    TopList