Лимит операций (op-limit) и как создать поток вручную

Добавлен , опубликован

Выполнение кода и обращение к данным

Содержание:
А теперь сюрприз! Каждый "поток" в Warcraft 3 имеет лимит операций. Как только выполнится определенное количество операций, варкрафт экстренно завершает поток и даже не сообщает об этом.
Скорее всего, это было сделано, чтобы избежать бесконечных циклов и различных ошибок зависания, допущеных дизайнерами во время написания карт Blizzard.
Подробнее про лимит операций с примерами можно посмотреть в теме XGM Forum - Прерывание потоков & limit op.

Что же теперь делать?!

За простые потоки волноваться не надо, а вот за поток инициализации различных баз данных стоит побеспокоиться и разбить его на новые потоки.

Как создать новый поток

Создать поток можно запуском одноразового таймера с минимальной задержкой, но в редких случаях я предлагаю не заморачиваться с таймерами и использовать функцию ExecuteFunc().
Простой пример:
function test3 takes nothing returns nothing
	много кода
endfunction

function test2 takes nothing returns nothing
	много кода
	call ExecuteFunc("test3")
endfunction

function test1 takes nothing returns nothing
	много кода
	call ExecuteFunc("test2")
endfunction

// ...
	call test1()
Пример с передачей параметров. Внимание: это работает хорошо только в Warcraft 3 и подобных! Как раз из-за того замечания про потоки.
На других, современных языках программирования появится проблема синхронизации данных.
globals
	unit test_receive_u = null
	int test_receive_i = 0
endglobals

function test_receive takes nothing returns nothing
	local unit u = test_receive_u
	local int i = test_receive_i
	
	// ваш код, глобальные в нем не используются,
	// потому что они могут быть перезаписаны другим потоком
	
endfunction

function test_send takes nothing returns nothing
	local unit u
	local int i
	
	// ваш код
	
	// передача аргументов в новый поток и создание нового потока
	set test_receive_u = u
	set test_receive_i = i
	call ExecuteFunc("test_receive")
	
	// Здесь внимание! Даже если вы вызовете TriggerSleepAction, 
	// новый поток продолжит выполняться. И это хорошо! =)
	
	// ваш код, например, обнуление (но не удаление) локальных юнитов
endfunction
Ещё два примера: раз, два.