Таймер в приложении командной строки
Попытка создать простое приложение командной строки в Haxe, у которого есть тикающий таймер, но, похоже, это не сработало; Таймер никогда не начинает тикать.
package;
import haxe.Timer;
class TimerCallback {
private static inline var CHAR_SPACE : Int = 32;
public static function main() : Void {
var myME = new TimerTicker();
while (Sys.getChar(false) != CHAR_SPACE) {
//loop until [space] detected, do nothing here
}
}
}
class TimerTicker {
private var myTimer : Timer = null;
public function new() {
myTimer = new Timer(20);
myTimer.run = timer_OnTick;
}
private function timer_OnTick() : Void {
Sys.println ("foobar");
}
/* destructor?! */
}
И это команда build:
>haxe.exe -lib nme -main TimerCallback -cpp .\bin
Если я не добавляю -lib nme
код не компилируется (на основе API документа все в порядке, так как таймер не поддерживается для cpp, поэтому доступны только статические функции)
Однако, если я добавлю это, код будет скомпилирован - так как nme поддерживает cpp Timers-, и исполняемый файл создан (win), но timer_OnTick()
никогда не называется. Итак, exe запускается, ничего не происходит, одним нажатием SPACE
и приложение. квиты.
Дополнительная информация:
- импортированные Timer.hx
это файл: haxe\lib\nme\5,1,8\haxe
, И если я прав, это должно быть хорошо и работает.
- Использование haxe 3.1.3, nme 5.1.8, hxcpp 3.1.39 (и haxelib 3.1.0-rc.4, если имеет значение)
Любая помощь приветствуется.
1 ответ
Хорошо, я получил помощь от сообщества Haxe (список рассылки). Вот решения, если кому-то они понадобятся:
КОД ПСЕВДО (не тестировался)
class RunLoop {
static var queue = new Deque<Void->Void>();
static var keepAlives:Int; = 1;
static public function release()
enque(function () keepAlives--);
static public function retain()
enque(function () keepAlives++);
static public function enque(task:Void->Void)
queue.add(task);
static function main() {
enque(entryPoint);
release();
}
static function entryPoint() {
//code goes here
}
static function run()
while (keepAlives:Int > 0)
queue.pop()();
}
//Now you can go an implement a timer like so:
class Timer {
var active:Bool = true;
public function new(msecs:Int) {
RunLoop.retain();
Thread.create(function () while(active) {
Sys.sleep(msecs / 1000);
if (active)
RunLoop.enque(this.run);
});
}
public dynamic function run() {}
public function stop() {
active = false;
RunLoop.release();
}
}
//And a helper for blocking code:
class Task {
var task:Void->T;
var onDone:T->Void;
public function new(task:Void->T, onDone:T->Void) {
RunLoop.retain();
Thread.create(function () {
var result = task();
RunLoop.enque(onDone.bind(result));
});
}
}
//So then the code you want would look roughly like this:
static function entryPoint() {
var timer = new Timer();
timer.run = function () trace('foobar');
function waitForSpace() {
while (Sys.getChar(false) != CHAR_SPACE) {
//loop until [space] detected, do nothing here
}
return true;
}
new Task(
waitForSpace,
function (_) timer.stop() //stop the timer so that the run loop can exit
);
}
(решение предоставлено back2dos)/*
1. Neko : works
2. C++: works, However, incrementing count in the if statement instead ( if( count++ == 0 ) { ... ) fails to increment count! Fixed on Git?
3. Flash : works
4. Java : fails using Haxe 3.1.3
*/
### build.hxml ###
-main Main
-swf main.swf
-swf-version 12
--next
-main Main
-neko main.n
--next
-main Main
-cpp cpp
-cmd cp cpp/Main ./main
--next
-main Main
-java java
-cmd cp java/Main.jar ./main-jar
### Main.hx ###
class Main {
public static function main() {
#if sys
var count = 0;
while( true ) {
if( count == 0 ) {
Timer.delay(function() trace("doThing1"), 3000);
Timer.delay(function() trace("doThing2"), 1000);
count++;
}
}
#else
Timer.delay(function() trace("doThing1"), 3000);
Timer.delay(function() trace("doThing2"), 1000);
#end
}
}
### Timer.hx ###
#if neko
import neko.vm.Deque;
import neko.vm.Thread;
import neko.vm.Mutex;
import neko.vm.Lock;
#elseif cpp
import cpp.vm.Deque;
import cpp.vm.Thread;
import cpp.vm.Mutex;
import cpp.vm.Lock;
#elseif java
import java.vm.Deque;
import java.vm.Thread;
import java.vm.Mutex;
import java.vm.Lock;
#end
class Timer {
#if sys
static var timerThread : TimerThread;
#else
static var timers : Array;
#end
static function __init__() {
#if sys
timerThread = new TimerThread();
#else
timers = [];
#end
}
public static function stop() {
#if sys
timerThread.quit();
#else
for( t in timers )
t.stop();
#end
}
public static function delay( func : Void -> Void, delayMillis : Int ) {
#if sys
timerThread.addTimer(delayMillis/1000, func);
#else
timers.push( haxe.Timer.delay(func, delayMillis) );
#end
}
} #if sys typedef TTimerData = {time: Float, func: Void -> Void
}
class TimerThread {var mutex: Mutex; var queueLock: Lock; var queue: Array; вар бег: Bool; публичная функция new() {
queue = [];
queueLock = new Lock();
mutex = новый Mutex(); бег = истина;
Thread.create( mainLoop);
} публичная функция addTimer( delaySec: Float, cb: Void -> Void) {
mutex.acquire();
var time = haxe.Timer.stamp() + delaySec; индекс var = 0;
while( index= queue[index].time)
index++;
queue.insert(index, { time: time, func: cb });
mutex.release();
queueLock.release();
} публичная функция quit(?cb: Void -> Void) {
var me = this;
addTimer( 0, function() {
me.running = false;
if( cb!= null)
cb();
});
}
function mainLoop() {
while(выполняется) {
var wake: Null = null;
var now = haxe.Timer.stamp();
var ready = new Array();
mutex.acquire();
while( queue.length > 0)
if( queue[0].time <= now)
ready.push(queue.shift());
else {
wake = queue[0].time; перерыв; } mutex.release (); for (готово d) {
d.func(); если (! работает) перерыв;
}
if(!running)
break;
if( wake == null)
queueLock.wait();
else {
var delay = wake - haxe.Timer.stamp();
if( delay > 0)
queueLock.wait(delay);
}
}
}
}
#конец (Решение предоставлено Zjnue, модифицированный код Хью)