Problem with threading (I think)

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Problem with threading (I think)

Aaron Wadley
Hi all!

I've got a rather complex appliction written in BeanShell and I'm having a
problem that I think is related to threading.  This is going to be a really
long post since I've got give some background and code samples.

First some background.  My application is currently called BAGS (Beany
Adventure Game System).  It is intended to be a full-fledge Interactive
Fiction engine.  If you've ever played old games like Zork or Adventure,
you're familiar with Interactive Fiction.  If you're not, it's basically a
text-based game system that the user interacts with by issuing text commands.

At any rate, I've got the bulk of the framework done, complete with a Swing
UI, but I'm having a problem implementing logic to wait for user input.
"Press any key to continue" type stuff.  I've got a method called
waitForKeyPress() that looks like this:

waitForKeyPress() {
    output.insertStyledString("[Press any key to continue]", STYLE_ITALIC);
    output.insertLineBreak();
    output.insertLineBreak();

    gui.addKeyListener(game);
    while(!gotInput) {
        Thread.sleep(1000);
        Thread.yield();
    }
    gotInput = false;
    gui.removeKeyListener(game);
}

The idea is that any object should be able to call this method and only
continue when a key was pressed.

This works great when I use it at the start of the game, but when called from
another object later, it locks up the gui and won't allow any input.

Here is the basic flow of the system:

There is a java class that starts the game by doing some initalization, then
calling the interpreter to source a bsh file and run it's runGame() method.
The rest is entirely BeanShell scripted objects.

Interpreter i = new Interpreter();
... do some initialization stuff
i.source("BAGSMain.bsh");
... do some more initialization stuff
i.eval("bagsMain.runGame()");

Here is the RunGame() method from BAGSMain.bsh

game;

runGame() {
    try {
        pwd();
        // Load the BAGS code
        source("BAGSGame.bsh");
    } catch(Exception ex) {
        ex.printStackTrace();
    }

    /** The BAGS game */
    game = Game();
    try {
        source(preloadFile);
    } catch(e) {
        e.printStackTrace();
    }
    game.displayIntro();
    game.showLocation();
}


The Game() scripted object contains the main logic and also contains the
waitForKeyPress() method.  The gui is created when the Game object is
instantiated.  The code in the preloadFile that is sourced from run game calls
game.waitForKeyPress() and works perfectly.  It is also called from
game.displayIntro() and again works perfectly.

Where it doesn't work is during the execution of some command from the user.
Game implements actionPerformed() and when the user hits enter, this kicks off
and processes the command.  Ideally, at some point during this execution, I'd
like to be able to wait for input from the user before continuing processing.

I suspect that the problem lies from being called while being in the event
subsytem of Swing.

The full source can be downloaded at
http://cyberlizard.org/downloads/BAGS_src_0.1_20050713.tar.gz
The bsh files are in the bin directory.

Thanks for listening to my rambling.  I'm going to keep digging, but any ideas
about a way to accomplish this would be fantastic.

--
==============================================================================
Aaron Wadley                                          [hidden email]
CyberLizard Industries                                  www.cyberlizard.org
==============================================================================



-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
Beanshell-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/beanshell-users
Reply | Threaded
Open this post in threaded view
|

RE: Problem with threading (I think)

White, John K


> -----Original Message-----
> From: [hidden email]
> [mailto:[hidden email]] On
> Behalf Of Aaron Wadley
> Sent: Thursday, July 14, 2005 8:30 AM
> To: [hidden email]
> Subject: [Beanshell-users] Problem with threading (I think)
>
>
>
> I suspect that the problem lies from being called while being
> in the event subsytem of Swing.

that's a good suspicion. AWT and hence swing is single-threaded.
any code invoked on a listener as a result of user input is running
on AWT's EventQueue thread. this queue is used to perform all
swing operations, like painting and input handling. so if you were to
execute a loop in code running in the event queue whose invariant
depends on something that can only be detected by some subsequent
swing action, you'll be waiting a long long time :).

coincidentally i have a similar problem in a context totally unrelated
to bsh. the best thing i could come up with is an "action interceptor"
pattern (i made that word up). it works like this:

1. UI sees event, sends to action interceptor
2. action interceptor sends event to listener
3a. listener writes out some text, then does "press any key to
continue"-type thing
3b. listener registers a handler for the post-key-press with the
interceptor
3c. listener returns, letting event queue continue
4. UI sees event, sends to action interceptor
5. action interceptor sees a handler has been registered, discards input
and invokes handler
6. handler may register another handler and then the cycle continues...

it's not very elegant at all and really complicates the action listener,
especially as i've got to do this in straight java rather than bsh, so i
end up with lots of anonymous classes. any better ideas are greatly
appreciated.

john


-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. <a href="http://ads.osdn.com/?ad_idt77&alloc_id492&op=click">http://ads.osdn.com/?ad_idt77&alloc_id492&op=click
_______________________________________________
Beanshell-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/beanshell-users
Reply | Threaded
Open this post in threaded view
|

RE: Problem with threading (I think)

Aaron Wadley
White, John K said:

>>
>> I suspect that the problem lies from being called while being
>> in the event subsytem of Swing.
>
> that's a good suspicion. AWT and hence swing is single-threaded.
> any code invoked on a listener as a result of user input is running
> on AWT's EventQueue thread. this queue is used to perform all
> swing operations, like painting and input handling. so if you were to
> execute a loop in code running in the event queue whose invariant
> depends on something that can only be detected by some subsequent
> swing action, you'll be waiting a long long time :).
>
> coincidentally i have a similar problem in a context totally unrelated
> to bsh. the best thing i could come up with is an "action interceptor"
> pattern (i made that word up). it works like this:
>
> 1. UI sees event, sends to action interceptor
> 2. action interceptor sends event to listener
> 3a. listener writes out some text, then does "press any key to
> continue"-type thing
> 3b. listener registers a handler for the post-key-press with the
> interceptor
> 3c. listener returns, letting event queue continue
> 4. UI sees event, sends to action interceptor
> 5. action interceptor sees a handler has been registered, discards input
> and invokes handler
> 6. handler may register another handler and then the cycle continues...
>
> it's not very elegant at all and really complicates the action listener,
> especially as i've got to do this in straight java rather than bsh, so i
> end up with lots of anonymous classes. any better ideas are greatly
> appreciated.
>

Sounds like a decent workaround.  What I ended up doing was implementing a
callback.  You set a flag and a string containing the method to call.  The
actionPerformed method checks the flag and dynamically invokes the method
specified.  It's not very elegant either.

What I really want is a kind of readline method that does the waiting inline
in the code so that I can continue once input has been received without having
to write code somewhere else.  The idea is that non-programmer types would be
writing the bsh code and I'd like it to be as simple as possible.

What about the actionPerformed method spawning another thread to do the work
of the action?  If I did the wait thing in that thread, the UI would be freed
up to continue.  I'd have to be careful about input occurring while the thread
was still running.  Hmmm... Sorry, I'm thinking out loud now.  I'm not that
experienced with explicitly managing threads like this.

Thanks for the feedback.  I'll play with some ideas and let you know what
happens.

--
==============================================================================
Aaron Wadley                                          [hidden email]
CyberLizard Industries                                  www.cyberlizard.org
==============================================================================



-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
Beanshell-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/beanshell-users
Reply | Threaded
Open this post in threaded view
|

RE: Problem with threading (I think)

Alexey Zinger


--- Aaron Wadley <[hidden email]> wrote:

>
> Sounds like a decent workaround.  What I ended up doing was implementing a
> callback.  You set a flag and a string containing the method to call.  The
> actionPerformed method checks the flag and dynamically invokes the method
> specified.  It's not very elegant either.
>
> What I really want is a kind of readline method that does the waiting inline
> in the code so that I can continue once input has been received without
> having
> to write code somewhere else.  The idea is that non-programmer types would be
> writing the bsh code and I'd like it to be as simple as possible.
>
> What about the actionPerformed method spawning another thread to do the work
> of the action?  If I did the wait thing in that thread, the UI would be freed
> up to continue.  I'd have to be careful about input occurring while the
> thread
> was still running.  Hmmm... Sorry, I'm thinking out loud now.  I'm not that
> experienced with explicitly managing threads like this.
>
> Thanks for the feedback.  I'll play with some ideas and let you know what
> happens.

I may be entirely off mark here, but have you guys tried using wait/notify mechanism?

Alexey
2001 Honda CBR600F4i (CCS)
1992 Kawasaki EX500
http://bsheet.sourceforge.net

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around
http://mail.yahoo.com 


-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
Beanshell-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/beanshell-users
Reply | Threaded
Open this post in threaded view
|

RE: <SOLVED!> Problem with threading (I think)

Aaron Wadley

Alexey Zinger said:

>
>
> --- Aaron Wadley <[hidden email]> wrote:
>>
>> Sounds like a decent workaround.  What I ended up doing was implementing a
>> callback.  You set a flag and a string containing the method to call.  The
>> actionPerformed method checks the flag and dynamically invokes the method
>> specified.  It's not very elegant either.
>>
>> What I really want is a kind of readline method that does the waiting inline
>> in the code so that I can continue once input has been received without
>> having
>> to write code somewhere else.  The idea is that non-programmer types would
>> be
>> writing the bsh code and I'd like it to be as simple as possible.
>>
>> What about the actionPerformed method spawning another thread to do the work
>> of the action?  If I did the wait thing in that thread, the UI would be
>> freed
>> up to continue.  I'd have to be careful about input occurring while the
>> thread
>> was still running.  Hmmm... Sorry, I'm thinking out loud now.  I'm not that
>> experienced with explicitly managing threads like this.
>>
>> Thanks for the feedback.  I'll play with some ideas and let you know what
>> happens.
>
> I may be entirely off mark here, but have you guys tried using wait/notify
> mechanism?

I thought about that, but I really wanted the wait to happen inline without
locking up the gui.  What I ended up doing was to create a separate thread
that gets called by the ActionListener.  That way, any wait that I do in that
separate thread won't lock up the gui.

actionPerformed(event) {
    String command;
    command = gui.commandInput.getText();

    output.insertStyledString("> " + command, STYLE_BLUE_BOLD);
    output.insertLineBreak();

    // Clear text area

    game.gui.commandInput.setText (new String());
    game.gui.commandInput.requestFocusInWindow();

    if (waitingForInput) {
        inputString = command;
        gotInput = true;
    } else {
        parser.commandString = command;
        Thread t = new Thread(parser);
        t.start();
    }
    //parser.parseCommand(command);
}

So in my code all I have to do is:

debug("Asking for more input");
                                                game.output.insertStyledString("Which door, the interior door or the
front door?\n", STYLE_ITALIC);
game.output.insertLineBreak();

// Here's where the wait magic happens.
cmdString = game.waitForInput();

debug("Response is " + cmdString);
if (cmdString.toUpperCase().matches("FRONT.*")) {
    game.output.insertString("A sturdy front door.");
} else if (cmdString.toUpperCase().matches("BEDROOM.*|INTERIOR.*")) {
    game.output.insertString("Your standard interior door.  More than likely
goes into a bedroom.");
} else {
    game.output.insertStyledString("I don't see that door here", STYLE_ITALIC);
}


--
==============================================================================
Aaron Wadley                                          [hidden email]
CyberLizard Industries                                  www.cyberlizard.org
==============================================================================



-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
Beanshell-users mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/beanshell-users