-
При использовании таймера из модуля MMSystem, в котором идёт вывод битмапа, через некоторое время происходит коллапс. Т.е. если потаскать форму или изменять её размеры рисование битмапа не происходит.
Вот примерный код:
var bmp:TBitmap; TimerSpectrId:UINT;
procedure Timer(uTimerlD, uMessage: UINT;dwUser, awl, dw2: DWORD);stdcall; begin bmp.Canvas.Brush.Color:=RGB(Random(256), Random(256), Random(256)); bmp.Canvas.Rectangle(0,0,100,100); Form1.Canvas.Draw(0,0,bmp); end;
procedure TForm1.FormCreate(Sender: TObject); begin bmp:=TBitmap.Create; bmp.Width:=100; bmp.Height:=100;
TimerSpectrId:=timeSetEvent(50, 1, @Timer, 0, TIME_PERIODIC); end;
-
Переименуй Timer, скажем в _Tmr0001, т.к. это там в ВЦЛ чего-то перекрывает, что возможно и является причиной.
-
> Efir © (06.09.07 14:54)
Мутьтимедийные таймеры работают в своих собственных дополнительных потоках, поэтому обращение к визуальным VCL-контролам в теле колбэк-процедуры Timer() недопустимо.
-
>Мутьтимедийные таймеры работают в своих собственных дополнительных потоках, поэтому обращение к визуальным VCL-контролам в теле колбэк-процедуры Timer() недопустимо.
Т.к. у Delphi нет средств, чтобы это проконтроллировать и пресечь, это вполне допустимо.
-
> у Delphi нет средств, чтобы это проконтроллировать
Да ты что ?! А мужики-то и не знают)
> и пресечь
Зачем пресекать-то ?
> это вполне допустимо
Угу. Только потом не надо при всем честнОм народе жаловаться на "глюки" и "коллапсы")
-
>Угу. Только потом не надо при всем честнОм народе жаловаться на "глюки" и "коллапсы")
Почему не надо? Надо. И требовать, чтобы потоки по-человечески сделали.
Про зачем пресекать по инерции спросил?
-
> требовать, чтобы потоки по-человечески сделали
Не понял... Кто у кого требовать должен ? И что значит "по-человечески" ?
> Про зачем пресекать по инерции спросил?
Нет не по инерции.
Зачем пресекать то что продумано разработчиком (в дан.случае разработчиками MS Windows) и очевидно ?
-
> Мутьтимедийные таймеры работают в своих собственных дополнительных > потоках, поэтому обращение к визуальным VCL-контролам в > теле колбэк-процедуры Timer() недопустимо.
Но тогда почему проблемы возникают именно с битмапом, который я трогаю только из потока. Проблема исчезает при использовании Lock, UnLock.
bmp.Canvas.Lock; bmp.Canvas.Brush.Color:=RGB(Random(256), Random(256), Random(256)); bmp.Canvas.Rectangle(0,0,100,100); Form1.Canvas.Draw(0,0,bmp); bmp.Canvas.UnLock;
-
> почему проблемы возникают именно с битмапом, который я трогаю > только из потока
Это не очевидно.
Зато очевидна засада в строчке
Form1.Canvas.Draw(0,0,bmp);
-
>Не понял... Кто у кого требовать должен ? И что значит "по-человечески" ?
Ты, я, Эфир, Дядя Фёдор, пёс и кот у КодеГеар. По-получеловечески значит хотя бы warning.
-
> у КодеГеар
Опять не понял)..
Что мы должны требовать у "КодеГеар" ? Чтобы он переделал функциональность timeSetEvent что ли ?
> хотя бы warning
Кто кого о чем должен предупреждать ?
-
>Сергей М. © (06.09.07 17:24) [10]
>TimerSpectrId:=timeSetEvent(50, 1, @Timer, 0, TIME_PERIODIC);
Вот здесь компилятор Delphi должен возопить, что callback будет выполняться в другом потоке, поэтому весь код в нём должен быть thread-safe.
-
> Сергей М. ©
Спасибо.
-
> sdubaruhnul (06.09.07 17:29) [11]
> здесь компилятор Delphi должен возопить, что callback будет > выполняться в другом потоке
С какого перепугу он должен "возопить" ?
Для компилятора ф-ция timeSetEvent - точно такая же как и сотни и тысячи других подпрограмм, генерацию кода вызова которых ты от него требуешь.
Компилятор знать не знает и знать не обязан о контексте работы вызванной подпрограммы, знать это положено нам как разработчикам прикладной логики. А знать это мы можем как минимум внимательно читая всякие мануалы и справки, где описывается логика работы той или иной интересующей нас п/программы.
Так что не городи уже чушь)
-
>Компилятор знать не знает и знать не обязан о контексте работы вызванной подпрограммы, знать это положено нам как разработчикам прикладной логики. А знать это мы можем как минимум внимательно читая всякие мануалы и справки, где описывается логика работы той или иной интересующей нас п/программы.
Если компилятор чего-то не знает, то он должен гарантировать безопасное выполнение кода в любом возможном случае.
Раз уж компилятор не знает, то среда должна предоставить безопасное решение таймера, пускай на основе того же MMSystem'ного таймера (TTimer не есть такое решение). С этим у Delphi вообще туго.
Так что не надо про чушь. Я читал много веток с твоим участием, про чушь ты любишь говорить. Так проще всего. Согласен, чуть-чуть дополнений ([7]) и всё работает и можно вроде бы не волноваться. Любые возражения - это чушь, потому что есть рабочий код. Пусть и в таком грязном стиле - функция API смешана с VCL. Но меня волнует стиль, и для меня это не чушь.
И не надо отсылать ко всяким мануалам. Разве oxfff не показал, что даже оператор присвоения недокументировано не thread-safe?
-
> Так что не городи уже чушь)
Двумя лапами поддержу. Чушь полнейшая. Среда ничего не обязана знать (да и не может), программист обязан перед использованием функции ознакомится с ее описанием в MSDN.
-
> Если компилятор чего-то не знает, то он должен гарантировать > безопасное выполнение кода в любом возможном случае
Ерунда полная. Пример ? Пожалуйста !
В BASM-блоке кода ты вправе такого нахреновертить, что мало не покажется не то что компилятору, а и самой ОС.
Вот как, скажи на милось, компилятор распознает опасность модификации того или иного сегментного регистра, если он сам дает тебе право его модифицировать, полагаясь на твои знания+разум и защищенность ОС от твоих неверных программных манипуляций ?
> среда должна предоставить безопасное решение таймера
Она и предоставляет. На основе того же TTimer. Но и с TTimer'oм при желании можно "наловить косяков".
Касаемо же подобного рода API-ф-ций среда полагается опять же на знания+разум программиста, предупреждая при этом о потоконебезопасности VCL.
-
>В BASM-блоке кода ты вправе такого нахреновертить, что мало не покажется не то что компилятору, а и самой ОС.
Мы говорим о языке Delphi или о BASM? Кажется, код из [0] был написан на Delphi. Кстати, об ассемблерных вставках недавно была ветка, где я выразил мнение о том, что их надо вообще запретить. Причина? Именно потому, что в ней "ты вправе такого нахреновертить, что мало не покажется не то что компилятору, а и самой ОС".
Теперь мой пример. Range checking. Или ты скажешь, что это тоже чушь? Что программист должен всегда проверять индекс в коде, а если пропустил, то искать непонятную AV? Кажется, есть такой язык - C - где проверки границ нет. И какова его область применения сейчас?
-
> [17] sdubaruhnul (07.09.07 12:11)
Плохая примета после грибочков писать на форуме. ^^
Запретить BASM? Ну извините, это мое дело, использовать его или нет. Если ты не в состоянии предугадать, какие неожиданности будут в результате выполнения того или иного кода - это твои проблемы как программиста, а не бедной среды, которая тебе так не угодила.
По поводу таймера. А если я напишу свой таймер, который будет выполняться в отдельном потоке, то как теперь несчастный компилятор должен выдавать предупреждения?
Вообще, ты и правда несешь чушь. Если что-то не получается сделать - это не повод тут же пинять на среду, компилятор и всех, под руку попавшхся.
> [0] Efir © (06.09.07 14:54)
Покопай в сторону синхронизации между потоками. Введи эти слова в поске и тут же найдешь много интересного.
-
>Запретить BASM? Ну извините, это мое дело, использовать его или нет. Если ты не в состоянии предугадать, какие неожиданности будут в результате выполнения того или иного кода - это твои проблемы как программиста, а не бедной среды, которая тебе так не угодила.
Очень показательно здесь слово "предугадать". Угадывай на здоровье.
Нафига нам BASM, об который спотыкается оптимизатор?
>По поводу таймера. А если я напишу свой таймер, который будет выполняться в отдельном потоке, то как теперь несчастный компилятор должен выдавать предупреждения?
Вот, в этом то весь вопрос. Ты не можешь себе представить, как это можешь быть осуществлено. Какие средства языка нужны для этого. Ты просто представляешь себе перед глазами работу потоков в Delphi и не понимаешь, куда там можно впихнуть проверку.
Просто для того, чтобы ты мог хоть немного пофантазировать, приведу простой пример из другого языка - Java. Если в каком-то методе может возникать исключение, то это указывается в объявлении метода после ключевого слова throws, и программа не откомпилируется, пока у этого исключения не будет обработчика.
Если ты удовлетворяешь требованиям, которые ты же с Сергеем М установил (про логическое мышление программиста), то сможешь расширить этот пример и до дельфийских потоков. И также вспомнишь, что подобные примеры есть даже в Делфи, причём довольно старые и успешные.
|