As every Haxe developer knows, you could use haxe.Timer.delayed() to delay function call for some time. But this function doesn't exist for Neko at all. Is there a way to achieve the same results?
Have to check it first but
function delayed(f, time) {
neko.vm.Thread.create(function() {
neko.Sys.sleep(time);
f();
});
}
might be the closest thing possible. The only cons is that application becomes multi threaded which could lead to serious problems.
I thought about your issue and I think the best way is to create your own Timer class for Neko. I made a Timer class for you:
NekoTimer.hx
package;
import neko.Sys;
class NekoTimer
{
private static var threadActive:Bool = false;
private static var timersList:Array<TimerInfo> = new Array<TimerInfo>();
private static var timerInterval:Float = 0.1;
public static function addTimer(interval:Int, callMethod:Void->Void):Int
{
//setup timer thread if not yet active
if (!threadActive) setupTimerThread();
//add the given timer
return timersList.push(new TimerInfo(interval, callMethod, Sys.time() * 1000)) - 1;
}
public static function delTimer(id:Int):Void
{
timersList.splice(id, 1);
}
private static function setupTimerThread():Void
{
threadActive = true;
neko.vm.Thread.create(function() {
while (true) {
Sys.sleep(timerInterval);
for (timer in timersList) {
if (Sys.time() * 1000 - timer.lastCallTimestamp >= timer.interval) {
timer.callMethod();
timer.lastCallTimestamp = Sys.time() * 1000;
}
}
}
});
}
}
private class TimerInfo
{
public var interval:Int;
public var callMethod:Void->Void;
public var lastCallTimestamp:Float;
public function new(interval:Int, callMethod:Void->Void, lastCallTimestamp:Float) {
this.interval = interval;
this.callMethod = callMethod;
this.lastCallTimestamp = lastCallTimestamp;
}
}
Call it like this:
package ;
import neko.Lib;
class Main
{
private var timerId:Int;
public function new()
{
trace("setting up timer...");
timerId = NekoTimer.addTimer(5000, timerCallback);
trace(timerId);
//idle main app
while (true) { }
}
private function timerCallback():Void
{
trace("it's now 5 seconds later");
NekoTimer.delTimer(timerId);
trace("removed timer");
}
//neko constructor
static function main()
{
new Main();
}
}
Hope that helps.
Note: this one has an accuracy of 100ms. You can increase this by decreasing the timerInterval setting.
I used the class as well, and I found one issue. Because is not completely realtime, it sleeps the interval, calls the function, and sleeps the interval again. So, depending on how long the function you are running takes, it ticks slower or faster.
I've solved it by replacing line 39 like so:
//timer.lastCallTimestamp = Sys.time() * 1000;
timer.lastCallTimestamp = timer.lastCallTimestamp + timer.interval;
Yes I don't know anything except for what you mention in your first answer. On Linux you can use SIGALARM - but this doesn't look trivial, 100% pure C code, and needs to be handled with great care to avoid crashing the VM.
Related
I have a java thread which is running a path-finding algorithm in a constant while loop. Then, every so often I want to retrieve the most updated path from the thread. However, I am unsure how to do this, and think I might be doing it wrong.
My thread consists of the following code:
public class BotThread extends Thread {
Bot bot;
AStar pathFinder;
Player targetPlayer;
public List<boolean[]> plan;
public BotThread(Bot bot) {
this.bot = bot;
this.plan = new ArrayList<>();
pathFinder = new AStar(bot, bot.getLevelHandler());
}
public void run() {
while (true) {
System.out.println("THREAD RUNNING");
targetPlayer = bot.targetPlayer;
plan = pathFinder.optimise(targetPlayer);
}
}
public boolean[] getNextAction() {
return plan.remove(0);
}
}
I then create an object of BotThread, and call start(). Then when I call getNextAction() on the thread, I seem to receive a null pointer. Is this because I am not able to call another method on the thread whilst it is in the main loop? How should I do this properly?
This is because you are not giving enough time to thread to initialise plan Arraylist. You need to add sleeping time to the threads. Something like this while calling BotThread class from main:
int num_threads = 8;
BotThread myt[] = new BotThread[num_threads];
for (int i = 0; i < num_threads; ++i) {
myt[i] = new BotThread();
myt[i].start();
Thread.sleep(1000);
myt[i].getNextAction();
}
Just ran into this issue in Haxe and was wondering if this was a bug or if it was done on purpose...
I was binding a function that prints a timestamp. The timestamp in this case was a getter in my globals class. I expected that if I were to wait a few seconds and then invoke the bound function, it would use the value of the getter at the time the function was bound. That was not the case. Instead, it seems to be calling the getter to get the current value each time.
I checked to see if this happens if I switched from using a getter to a normal function call to fetch my timestamp as my parameter. The latter works as expected.
function printTime(time:Int):Void {
trace("The time is: " + time);
}
var p:Void->Void = printTime.bind(Globals.timestampgetter);
var p2:Void->Void = printTime.bind(Global.timestampfunc());
// wait 5 seconds
p(); // prints CURRENT timestamp, i.e. adds the 5 seconds that passed
p2(); // prints time at which printTime.bind was called
EDIT:
Forgot to mention... I'm using Haxe 3.1.3 and OpenFL 3.0.0 beta, compiling to a Flash target.
After some more tries I reduced the test case to the following and I can confirm that it is a bug in the Flash generator. I reported it here: https://github.com/HaxeFoundation/haxe/issues/4089
class Test {
static function main() {
function printTime(time:Float)
trace("The time is: " + time);
timestamp = timestampfunc();
var t = timestampfunc();
var p1 = printTime.bind(timestamp);
var p2 = printTime.bind(t);
var p3 = printTime.bind(timestampfunc());
p1();
p2();
p3();
haxe.Timer.delay(function() {
t = timestamp = timestampfunc();
p1();
p2();
p3();
}, 1000);
}
public static var timestamp : Float;
static function timestampfunc() return Date.now().getTime();
}
I tried your code and it works as expected for me. The values are set at bind time and do not change even if you delay the calls of p and p2.
Here is the code I tested:
class Test {
static function main() {
function printTime(time:Float):Void {
trace("The time is: " + time);
}
var p = printTime.bind(Test.timestampgetter);
var p2 = printTime.bind(Test.timestampfunc());
p();
p2();
haxe.Timer.delay(function() {
p();
p2();
}, 1000);
}
public static var timestampgetter(get, null) : Float;
static function timestampfunc() return Date.now().getTime();
static function get_timestampgetter() return Date.now().getTime();
}
You can test it yourself here: http://try.haxe.org/#C85Ce
Interesting... the problem seems to stem from using "default" instead of "get" for the getter.
Franco's code works. But this code doesn't:
class Test {
static function main() {
function printTime(time:Float):Void {
trace("The time is: " + time);
}
updateTimestamp();
var p = printTime.bind(Test.timestampgetter);
var p2 = printTime.bind(Test.timestampfunc());
p();
p2();
haxe.Timer.delay(function() {
p();
p2();
}, 1000);
}
static function updateTimestamp():Void {
timestampgetter = Date.now().getTime();
haxe.Timer.delay(updateTimestamp, 1000);
}
public static var timestampgetter(default, null) : Float;
static function timestampfunc() return Date.now().getTime();
static function get_timestampgetter() return Date.now().getTime();
}
I am getting started with Haxe and OpenFl, and have some experience with Javascript and Lua.
It was going pretty well, till I got to a point where I needed a function similar to wait() in Lua, etc, which stops the script until the number of seconds you set is over.
How would I go about doing this?
EDIT: To clarify, I am building to Flash.
Although this is old, I wanted to add another point for reference. The OP mentioned in a comment this was for a game. One method I often use is (and could probably be put in a library):
var timerCount:Float = 0;
var maxTimerCounter:Float = 5;
function update () {
timerCounter += elapsedTime;
if (timerCounter > maxTimerCounter){
onTimerComplete();
timerCount = 0;
}
}
In SYS you are looking for:
static function sleep( seconds : Float ) : Void
Suspend the current execution for the given time (in seconds).
Example: Sys.sleep(.5);
http://haxe.org/api/sys/
Edit: User is porting to flash.
So the suggestion is to use Timer
http://haxe.org/api/haxe/timer
In Timer the suggestion is to use
static function delay( f : Void -> Void, time_ms : Int ) : Timer
Someone on stack overflow has an example that looks like this: haxe.Timer.delay(callback(someFunction,"abc"), 10); located here... Pass arguments to a delayed function with Haxe
For the Flash compile target, the best you can do is use a timer, and something like this setTimeout() function.
This means slicing your function into two - everything before the setTimeout(), and everything after that, which is in a separate function that the timeout can call.
so somethine like, eg:
tooltipTimerId = GlobalTimer.setTimeout(
Tooltip.TOOLTIP_DELAY_MS,
handleTooltipAppear,
tootipParams
);
[...]
class GlobalTimer {
private static var timerList:Array<Timer>;
public static function setTimeout(milliseconds:Int, func:Dynamic, args:Array<Dynamic>=null):Int {
var timer:Timer = new Timer(milliseconds);
var id = addTimer(timer, timerList);
timer.run = function() {
Reflect.callMethod(null, func, args);
clearTimeout(id);
}
return id;
}
private static function addTimer(timer:Timer, arr:Array<Timer>):Int {
for (i in 0...arr.length) {
if (null == arr[i]) {
arr[i] = timer;
return i;
}
}
arr.push(timer);
return arr.length -1;
}
public static function clearTimeout(id:Int) {
var timers:Array<Timer> = GlobalTimer.getInstance().timerList;
try {
timers[id].stop();
timers[id] = null;
} catch(e:Error) {/* Nothing we can do if it fails, really. */}
}
}
i want to use keyPressed function in canvas class. but i do not want immediately call this function.
i try to use wait function but it cause an error ( i think it hasn't any use for this). what should i do?
keyPressed is called by the AMS (Application Management Software) when the user clicks a key. You cannot delay that.
But you can of course call keyPressed yourself as you want. If you want to call keyPressed 10 seconds from now, you should create a Thread with a timer and a loop that asks if 10 seconds has gone by now.
Something like this: (not tested)
class keyPressedAfterSeconds implemments Runnable {
MyCanvasObject myCanvas = null;
int seconds = 10; // Default
long startTime;
public keyPressedAfterSeconds(MyCanvasObject myCanvas, int seconds) {
this.myCanvas = myCanvas;
this.seconds = seconds;
new Thread(this).start();
}
public run() {
startTime = System.currentTimeMillis();
while(System.currentTimeMillis()-startTime<seconds*1000) {
try { // Wait 100 ms and ask again
Thread.sleep(100);
} catch (Exception e) {}
}
myCanvas.keyPressed(someKeycode);
}
}
Hi i am trying to grab a value from my threading but it seem work not so find to me course i found that my code structure are unstable enough..here is my code i name my thread class as "clsThreadCount" and below is my implementation
public volatile bool Grab = false;
public volatile int count = 0;
public void Initialization(int i)
{
count = i;
}
public void Play()
{
Grab = false;
_shouldStop = false;
ThreadTest();
}
public void Stop()
{
_shouldStop = true;
workerThread.Join(1);
workerThread.Abort();
}
private void ThreadTest()
{
workerThread = new Thread(DoWork);
workerThread.Start();
while (!workerThread.IsAlive) ;
}
private void DoWork()
{
try
{
while (!_shouldStop)
{
if (Grab)
{
count++;
Grab = false;
}
}
}
catch (Exception)
{
Play();
}
finally
{
}
}
when my program(main menu) are starting to run i will trigger the initialize function at pass the parameter as 7
ObjThreadCount.Initialization(7); // count = 7
ObjThreadCount.Play(); // the thread are running
ObjThreadCount.Grab = true; // the grab equal to true, count++ are trigger
Thread.Sleep(100); // wait awhile
lblResult.Text = ObjThreadCount.count.ToString(); // sometime i can get count++ result (e.g. 8)
ObjThreadCount.Stop(); // thread stop
sometime my program can able to get a right counting from the thread but sometime are not.
i realize at my while loop implementation there are something are missing..
something like waitone or waitautoevent..can i ignore Thread.Sleep(100) ?? what are the suitable code should i add in the while loop ?
Please help me~ :S
** sorry in the first upload i forgot to write down "volatile" into the variable
thank you..
If C# (and C and java, and probably C++), you need to declare _shouldStop and Grab as volatile.