Вверх ↑
Этот топик читают: Гость
Ответов: 1429
Рейтинг: 50
#1: 2012-02-14 09:32:06 ЛС | профиль | цитата
Нужно запустить параллельный поток в FTCG мультике. Как это сделать?

Для начала,

1. От какого класса его наследовать?
2. Какие есть подводные камни и т. п.?

Жду Вашей помощи.
карма: 0

0
Ответов: 3889
Рейтинг: 362
#2: 2012-02-14 09:54:37 ЛС | профиль | цитата
login,
1. объявляем в приватной секции: thrd:PThread
2. При создании потока для Free Pascal нужно делать
thrd := NewThreadForFPC
2.1 Для другого компилятора
thrd := NewThread
2.2 Указываем какую функцию будем исполнять в потоке:
thrd.OnExecute := ИмяФункции
2.3 Включаем самоуничтожение потока после отработки:
thrd.AutoFree := true
2.4 Запускаем поток на исполнение:
thrd.Resume
карма: 1

1
Голосовали:login
Ответов: 1429
Рейтинг: 50
#3: 2012-02-14 10:09:16 ЛС | профиль | цитата
1nd1g0, шикарно!

Скажите, а создание потока ресурсоёмкая процедура?
Чисто практически, если мой интерфейс рисует 50 кадров в секунду, при том, что один кадр это полный цикл отдельного суб-мультика,
мне нужно запускать/уничтожать отдельный поток 50 раз в секунду, или нужно держать поток постоянно работающим, и по условию переменной-ключа выполнять его работу или не выполнять? (может вопрос глупый, но я мало о таком знаю)
карма: 0

0
Разработчик
Ответов: 26324
Рейтинг: 2147
#4: 2012-02-14 10:39:28 ЛС | профиль | цитата
login писал(а):
а создание потока ресурсоёмкая процедура?

Да, ресурсоемкая. Основное время тратится на выделение сегментов памяти под кучу порожденного потока. Чем сильнее загружена система, тем дольше времени уходит на выделение памяти
карма: 22

0
Ответов: 1429
Рейтинг: 50
#5: 2012-02-14 22:15:34 ЛС | профиль | цитата
Сделал код элемента, который генерит вот это:
code_26875.txt

Но в строке 104 - "thrd.OnExecute := Execute7;", ошибка:
Error: Incompatible types: 'Integer' and 'procedure, untyped pointer or untyped parameter'


Код элемента на всякий случай:

#hws
func init()

fvar(e)
e = code(cgt.el_get_code_name(cgt.el_get_parent_id()))

fvar(old)
old = block.select(BLK_PRIV_MTD)

println('thrd:PThread;')
println('procedure Execute',code(_id_),'(Obj:PObj);')

block.select(BLK_MTD_BODY)
println ('procedure TClass',e,'.Execute',code(_id_),';')
println ('begin')
event(onExec)
println ('end;')

block.select(old)
end




func doStart()
println('thrd := NewThread;')
println('thrd.OnExecute := Execute',code(_id_),';')
println('thrd.AutoFree := true;')
println('thrd.Resume;')
end

func doStop()

end



карма: 0

0
файлы: 1code_26875.txt [2.5KB] [135]
Ответов: 16884
Рейтинг: 1239
#6: 2012-02-14 22:38:21 ЛС | профиль | цитата
login, вот у меня вопрос : Тебе кто-нибудь рассказывал про потоки на пальцах ?
Хотя-бы про то, что каждый созданый тобой "паралельный" поток замедляет работу программы ?
карма: 25
Немного терпения! Дежурный экстрасенс скоро свяжется с Вами!
0
Ответов: 1429
Рейтинг: 50
#7: 2012-02-14 22:50:18 ЛС | профиль | цитата
Tad, конечно не рассказывал.

Логика у меня такая. Есть сложный, ресурсоемкий, интерфейс, если на нем скопилось 4000 обьектов, то пока он их не "нарисует", никаких нот он на выход сыграть не сможет. А мне надо чтобы интерфейс тормозил сколько ему угодно, но поток нот не прерывался.
------------ Дoбавленo в 22.50:
Да, еще, многопроцессорные машины нужно использовать не на одно ядро. Я так понимаю, что многопоточное приложение использует больше ядер.
карма: 0

0
Администрация
Ответов: 15295
Рейтинг: 1519
#8: 2012-02-14 23:11:26 ЛС | профиль | цитата
login писал(а):
мне нужно запускать/уничтожать отдельный поток 50 раз в секунду

если задача поставлена таким образом, то это говорит о неверно выбранной архитектуре приложения. Изложите вашу исходную задачу - наверняка все можно решить гораздо проще
карма: 26
0
Ответов: 1429
Рейтинг: 50
#9: 2012-02-15 04:23:44 ЛС | профиль | цитата
Dilma, нет, это я просто спросил как делать. Я не утверждаю.

Архитектура такая:
В мультике FTCG есть два больших суб-мультика:

1. Интерфейс
2. Миди Секвенсер (позже, будет еще и аудио секвенсер)

1. Интерфейс:
Ему на вход подается doRefresh и он перерисовывает один кадр интерфейса, с текущим положениям масштаба и смещения поля. Событие doRefresh вызывается в случае если на интерфейсе что-то изменилось. (если юзер двигает поле, то это непрерывный поток кадров)
[offtop]интерфейс состоит из подмультиков, каждый из которых рисует свой слой обьектов (сетка, нотки, надписи, клипы и т. д.)[/offtop]
2. Миди секвенсер:
Наполняет маленький буфер, который в свою очередь, по таймеру, вызывает midi-события непрерывно(играет).

Оба мультика работают с одним и тем-же крупным массивом свойств. Во время работы они, то пишут, то читают, свойства обьектов.
[offtop]у каждого обьекта есть графические и музыкальные свойства.[/offtop]

выглядит так, только звука не будет:
Интерфейс33.rar


------------ Дoбавленo в 04.23:
Хотя, конкуренты меня озадачили. Они могут выводить количество клипов столько-же сколько и я. Тормоза, примерно, те-же.
Но. На самих клипах, они могут рисовать сотни тысяч обьектов!. Количество тормозов не меняется от того есть на клипах что-то или нет.

Как?! Сначала я подумал, что это PNG-шки, но эти клипы растягиваются, по осям без артефактов вместе с рисунками. Да и изменить размер сотен тысяч PNG-шек не просто. У них как будто и не происходит никакой работы.

reaper.png
reaper2.png
карма: 0

0
файлы: 3Интерфейс33.rar [55.7KB] [81], reaper.png [75.5KB] [421], reaper2.png [87.4KB] [452]
Ответов: 3889
Рейтинг: 362
#10: 2012-02-15 08:53:08 ЛС | профиль | цитата
login писал(а):
Как?!

При выводе может использоваться аппаратное ускорение векторной графики. Кроме того там явно применяется отбрасывание мелких элементов.
login писал(а):
Сначала я подумал, что это PNG-шки, но эти клипы растягиваются, по осям без артефактов вместе с рисунками. Да и изменить размер сотен тысяч PNG-шек не просто

Можно просчитать заранее набор текстур разного масштаба. Но там, скорее всего, используется приведение к одной, упрощённой векторной группе и отрисовка DirectDraw/OpenGL/GDI+/WPF (с аппаратным ускорением по возможности).
карма: 1

0
Ответов: 1429
Рейтинг: 50
#11: 2012-02-15 09:17:00 ЛС | профиль | цитата
[flood]Это, наверное, один из самых качественных интерфейсов. Такой быстрый софт далеко не у всех. Допустим, в Reason, скорость с нарисованными нотками на клипах где-то в 100 раз медленнее!. 10 треков аналогично фоткам которые я показал выше с трудом можно промотать, полный ступор. И нет оптимизации "отсечения невидимого" (как я сделал по формуле Леонида). Как я буду делать еще не решил. OpenGL рисует быстро, но зато загрузка текстур медленная. И не похоже, что у Reaper OpenGL отрисовка. Насчет аппаратных ускорений, скорее всего Вы правы, другого пути тут нет.[/flood]

1nd1g0, гляньте мою ошибку с параллельным потоком. Что с ней можно сделать.

1nd1g0 писал(а):
Кроме того там явно применяется отбрасывание мелких элементов.

Не применяется. Рассматривал с экранной лупой.

Делаю тесты, попробую рисовать в OpenGL.
карма: 0

0
Ответов: 3889
Рейтинг: 362
#12: 2012-02-15 18:37:27 ЛС | профиль | цитата
login писал(а):
гляньте мою ошибку с параллельным потоком. Что с ней можно сделать.

1nd1g0 писал(а):
2.2 Указываем какую функцию будем исполнять в потоке:
thrd.OnExecute := ИмяФункции

Объявляйте в приватной секции функцию вида:

function ИмяФункции(Sender:PThread):Integer
------------ Дoбавленo в 18.23:
login писал(а):
Не применяется. Рассматривал с экранной лупой

Ну как же, лупа глубже пикселя не заглянет, если нот 10 а линий пикселей 8, то отображено будет максимум 8 (в реальности - ещё меньше), хоть под чем рассматривайте
------------ Дoбавленo в 18.37:
login, да, чуть не забыл сказать, в функции можно крутить основной цикл пока Sender.Terminated не равен True (флаг завершения потока), потом Result := 0 (код отсутствия ошибок) и end

Если у Вас не получится таким, "высокоуровневым" способом организовать поток (хотя у Вас, вроде, уже всё необходимое на руках), то можно начать играться с CreateThread, но там несколько менее наглядно и повышается риск ошибок.
карма: 1

1
Голосовали:login
Ответов: 1429
Рейтинг: 50
#13: 2012-02-16 12:21:00 ЛС | профиль | цитата
1nd1g0, Заработало сразу, как только исправил! СпасибО!!!



------------ Дoбавленo в 08.44:
Неприятности, и вопрос скорее всего к Dilma:
кодогенератор отказывается печатать последний END; Останавливается на последней функции:


#hws
func Terminated_()

println (' if (1 = 1) then')
println ('begin')
return(onTerminated)
println ('end;') // это не печатает!

end
При этом эта функция последняя, и даже никуда не ведет.
onTerminated зарегистрирован в func init() как:

#hws
lng.decl_priv_var(onTerminated, 'integer')

Если сделать так:

#hws
func Terminated_()

println (' if (1 = 1) then')
println ('begin')

println ('end;')

end
- то печатает нормально..
Вот весь код элемента, на всякий случай:

#hws
func init()
fvar(e,result)
e = code(cgt.el_get_code_name(cgt.el_get_parent_id()))

fvar(old)
lng.decl_priv_var(onTerminated, 'integer')

old = block.select(BLK_PRIV_MTD)
println('thrd:PThread;')
println('function Execute',code(_id_),'(Sender:PThread):Integer;')



block.select(BLK_MTD_BODY)
println ('procedure TClass',e,'.Execute',code(_id_),';')
println ('begin')
event(onExec)

println (' if (Sender.Terminated = true) then')
println ('begin')
event(onStop)
println ('end;')
println ('end;')
block.select(old)
end


func doStart()
println('thrd := NewThread;')
println('thrd.OnExecute := Execute',code(_id_),';')
println('thrd.AutoFree := ',FastStop,';')
println('thrd.Resume;')
end


func doPause()
println('thrd.Suspend;')
end

func doResume()
println('thrd.Resume;')
end

func doStop()
println('thrd.Terminate;')
end

func Terminated_()

println (' if (1 = 1) then')
println ('begin')
return(onTerminated)
println ('end;')
end

if (1 = 1) - не обращайте внимание там будет другое условие

Подготовка к сборке проекта...
Генерация кода целевого языка
Компоновка проекта...
Command line: dcc32.exe "C:\Program Files\HiAsm\Elements\delphi\code\Тест Потоков FTCG.dpr" "-UC:\Documents and Settings\1\Рабочий стол\HiFT_Thread\." -Q
Borland Delphi Version 12.0 Copyright (c) 1983,98 Inprise Corporation

C:\Program Files\HiAsm\Elements\delphi\code\WinLayout.pas(159) Warning: Variable 'd' might not have been initialized

C:\Program Files\HiAsm\Elements\delphi\code\WinLayout.pas(176) Warning: Variable 'd' might not have been initialized

C:\Program Files\HiAsm\Elements\delphi\code\WinLayout.pas(40) Hint: Private symbol '_onObjDestroy' declared but never used

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools.pas(59) Hint: Variable 'PrevNeedInit' is declared but never used in 'THIFTCG_Tools.CreateInstance'

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(45) Warning: Return value of function 'TClassFTCG_Tools_8EA8B00.Execute5' might be undefined

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(124) Error: ';' expected but '.' found

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(126) Error: Declaration expected but end of file found

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(14) Hint: Private symbol 'readData' declared but never used

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(15) Hint: Private symbol 'readDataInt' declared but never used

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(16) Hint: Private symbol 'readDataStr' declared but never used

C:\Program Files\HiAsm\Elements\delphi\code\hiFTCG_Tools_8EA8B00.pas(17) Hint: Private symbol 'readDataReal' declared but never used

C:\Program Files\HiAsm\Elements\delphi\code\hiMainForm_8E38B90.pas(11) Fatal: Could not compile used unit 'hiFTCG_Tools_8EA8B00.pas'
Сборка завершена.


------------ Дoбавленo в 12.21:
Еще есть вопросы по потокам:

1. Два потока не могут одновременно записать в один массив, будет ошибка, а прочитать они одновременно смогут?
2. Как поставить защиту на массив(или переменную), чтобы пока один поток в него пишет, второй подождал?
карма: 0

0
Разработчик
Ответов: 26324
Рейтинг: 2147
#14: 2012-02-16 12:25:20 ЛС | профиль | цитата
login писал(а):
Как поставить защиту на массив(или переменную), чтобы пока один поток в него пишет, второй подождал?

Создать критическую секцию
login писал(а):
Два потока не могут одновременно записать в один массив, будет ошибка, а прочитать они одновременно смогут?

Смогут, но при наличии кртической секции -- не смогут

Критическа секция блокирует все остальные потоки от доступа к данным, занятыми обрабатывающим потоком. У критической секции есть два режима работы -- подвесить остальные потоки до разрешения доступа, или освободить их, для выполнения ими чего-либо своего. Существует две разновидности критических секций -- локальная, работающая только в пределах главного потока одного приложения, и глобальная, работающая между потоками приложений в системе, глобальная называется Mutex. Mutex еще используют для блокирования запуска нескольких копий одного приложения.

Для ознакомления с принципами работы ПО в многопоточных системах настоятельно рекомендую почитать книгу Джеффри РИХТЕР-а "Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows"

В пакете Windows есть компонент критической секции -- SafeMode/ Советую ознакомиться с кодом этого компонента и принципом построения критической секции
карма: 22

1
Голосовали:login
Ответов: 1429
Рейтинг: 50
#15: 2012-02-16 12:43:58 ЛС | профиль | цитата
nesco, доходчиво, спасибо!

Книжку уже скачал, спасибо!
карма: 0

0
Сообщение
...
Прикрепленные файлы
(файлы не залиты)