This site requires JavaScript, please enable it in your browser!
Greenfoot back
MrBradley
MrBradley wrote ...

2017/6/14

Simple Threading in Greenfoot

MrBradley MrBradley

2017/6/14

#
I am trying to introduce concurrency in my classes and wish to stay within the GF environment and simulator we use. One simple scenario I am considering is a read/display only task where the count of the number of overlapping actors is displayed (painted) on the actors. The idea is to spawn a thread for this actor and every time the stack count changes to update the display. When the stack count is zero the run method finishes. For example, the actor can be a stackable mineral deposit than can be mined by other actors. The miners are not threaded, only the mineral deposits. It is fine if we lose a signal (counts are off), or generate exceptions due to sequencing (object has been removed), but I'd like to explore concurrency related issues and work towards a (correct) solution as much as is possible in GF. The goal is to educate and discuss the various issues related to concurrent programming. It is entirely acceptable, indeed welcome, for students to experience various concurrency issues. Many of my students are interested in moving on to game programming, and this introduction is essential in gaming environments. I'd like to get a bit of a heads up from folks who have explored this in GF on the issues ahead and what to look for, or stay away from, and what can be worked around, and what does work. Once completed, I will post a sequence of scenarios with comments for those interested in exploring the topic. I will also post and update this thread with the example as we work through it. Thanks.
MrBradley MrBradley

2017/6/15

#
Here is the MineralDeposit class (GF version 3.0.4);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)
import java.util.List;
import java.awt.Font;
import java.awt.Color;
 
/**
 * MineralDeposit is a threaded actor that displays the stack count of deposits in a thread
 *
 * @author Mr Bradley
 * @version 1.3.0
 */
public class MineralDeposit extends Actor implements Runnable
{
    public MineralDeposit()
    {
    }
 
    /**
     * Act - this method is protected from running more than once.
     * It is responsible for setting up and starting the animation thread for the stack counts
     */
    boolean runOnce = false;
    public void act()
    {
        if(runOnce) return;
 
        runOnce = true;
        lock = ((MyWorld)getWorld()).lock;  // sychronization lock owned by the world
        displayThread = new Thread(this);
        displayThread.start();
        // the thread must terminate on its own now.
 
    }   
 
    public void run()
    {
        int currentStacks = 1;       
        // after updating the stack count, the thread waits until notified by
        // the world after a new stack has been added or removed.
        // This is an more efficient use of the CPU.
        System.out.print("\nThread " + Thread.currentThread().getName() + " Started.");
 
        while( hasStacks() && !terminated )
        {
            synchronized (lock)
            {
                currentStacks = getStackCount();    // this needs to be in the synchronized block
                                                    // its value can be changed outside of this thread
                if( this.stacks != currentStacks )
                {
                    this.stacks=currentStacks;
                    paintStackCount();
                }
 
                try {
                    lock.wait();
                    System.out.print(" " + this.stacks);
                } catch (InterruptedException e ) {}
            }
        }
        // thread terminates
        // It is important that the thread remove the object when it terminates
        // otherwise the object may be removed before it completes - this will cause an exception
        // and could lead to orphaned threads.
 
        System.out.print("\nThread " + Thread.currentThread().getName() + " Terminated.");
        getWorld().removeObject(this);
    }
 
    /**
     * this method should only be called within a sychronized block
     */
    public int getStackCount()
    {
        return getObjectsAtOffset(0, 0, MineralDeposit.class).size();
    }
 
    public void paintStackCount()
    {
        paintStackCount(stacks);
    }
 
    private void paintStackCount(int count)
    {
        GreenfootImage image = null;                    // create a local image
        image = new GreenfootImage(this.image);         // clear image to base so new count can be painted
        String label = String.valueOf( count );
        int length = label.length();
 
        image.setFont( new Font(Font.MONOSPACED, Font.BOLD, 12) );
        image.setColor(Color.black);
        image.drawString(label, (image.getWidth()-(length*4))/2, image.getHeight()/2+4);
        setImage(image);
    }
 
    public boolean hasStacks()
    {
        return stacks > 0;
    }
 
    public void terminate()
    {
        terminated = true;
    }
 
    /**
     * instance variables
     */
    private GreenfootImage image = new GreenfootImage("rock2.png");
 
    private boolean terminated = false; // flag to terminate thread
 
    private int stacks = 1;                 // if this exists there is at least one
    private Thread displayThread = null;    // display thread
    private Object lock = null;             // world lock
}
Any comments or suggestions are welcome.
Super_Hippo Super_Hippo

2017/6/15

#
I have never (successfully) used Threads, so I don't know if they are really so important. I think you are using this only as an example, but to do the same task, you could just give one mineral object a value and decrease it whenever it is mined instead of placing a lot of actors on top of each other.
MrBradley MrBradley

2017/6/15

#
The primary purpose of the example is as a teaching tool, and you are seeing just the final solution. This is a simplified example extracted from our classroom simulator, where the (Mineral Deposit) actors are separate and distinct objects, that may be stacked at any location in any combination at any given time. The key point is on line 56, there the execution of the thread is suspended, and is no longer using CPU resources. Without the use of threads this action would be repeated unnecessarily chewing up CPU cycles, and degrading performance. Imagine going to a high traffic website and having to wait in queue for your response to view the page. Concurrency allows the website to respond to a large number of requests without the delays associated with single threading. Using Greenfoot I can demonstrate concurrency related issues visually. A very common use for threads in gaming is for animations. If you have several actors that are being animated, the work to do this can cause the main playing loop to degrade in performance. If you are running a computer that has several core processors (and most do today), these would be un-utilized in a single threaded environment (like GF). A simple technique like the one in this example can offload the animations to other cores and keep the game running smoothly. BTW, I wanted to look at your PacMan scenario, but I couldn't find the link. Can you post a link for it?
Super_Hippo Super_Hippo

2017/6/15

#
I wish my teacher had any knowledge about programing when he introduced GF to us... It looks like you know what you are doing and hopefully your students can follow your thoughts. Usually you will get an answer like "Greenfoot is not thread-safe" from the GF team. Since I am not really into this, I can't tell you what you can do against this... GF is for beginners and that's why it gives you an environment without the need of using complicated java things. When I tried porting GF scenarios to android using Droidfoot, I had to use eclipse and I didn't have a clue about anything. I probably wouldn't ever had fun programing if I didn't find the simple and beginner-friendly GF. You should still be able to do anything you want though. ---------------------------------------------------- For the Pac-Man game: the game is right on the site where you wrote your comment: http://www.greenfoot.org/scenarios/19573 Maybe I will try to have like a bigger black border at the side of the world, so it doesn't look like that... But that's a general problem using the GF website with the only working browser IE.
You need to login to post a reply.