1
votes

I am working on a game using the thread-per-client model. The game operates so that every half a second all of the players need to be updated. The updates all have to happen within the half a second interval, so they need to all be executed at the same time. My idea is to have a class that keeps track of when the "global update" needs to happen and then when the time comes, go through all of the players and tell it to update:

 for(Player p : currentPlayers) {
     p.update();
 }

The problem is that since every player has their own thread, I want the player to take advantage of that fact since it is already there. If I go through the updates from a different class, then there is one thread executing what a couple hundred threads could be doing individually. How can I design it so that if a thread calls method 'update()' in class Player, a different thread than the one that called it executes it, or perhaps a different approach that can achieve the same goal?

If you need any clarification, please ask! Thanks a lot!

UPDATE: What do you guys think of this (I can't figure out how to format long amounts of code in posts!):

UPDATE 2: Just realized I would need to know when all of the players finish updating to reset the last time...

public class PseudoExample implements Runnable
{
    // Assume 'players' is full of active players.
    private Player[] players = new Player[100];
    private long lastUpdate = System.currentTimeMillis();

    public void run()
    {
        while (true)
        {
            if (System.currentTimeMillis() - lastUpdate >= 500)
            {
                for (Player p : players)
                {
                    p.update = true;
                }
            }

            try
            {
                Thread.sleep(10);
            } catch (InterruptedException e)
            {

            }
        }
    }

    private class Player implements Runnable
    {
        private boolean update = false;

        public void run()
        {
            while (true)
            {
                if (update)
                {
                    // Do updating here ...
                }

                try
                {
                    Thread.sleep(10);
                } catch (InterruptedException e)
                {

                }
            }
        }
    }
}
1
The only way to execute a method from a different thread is to execute it from a different thread. Queues are useful to pass around control information. However, this design is starting to sound ... complicated. KISS; especially with threading.user166390
It's not as difficult as it sounds. I'm thinking of trying kind of a 'ready-to-update' flag, and then once each thread does its update, it resets the flag.Martin Tuskevicius
No, that really is difficult. Why are multiple threads needed? How does interaction between the threads work? How/where is synchronization controlled? How is time sharing and event processing kept in-order? etc, etc. Threading will actually slow down a program unless there are things being parallized. And it's hard to get those correct, especially in situations with lots of shared state. Threads are not Actors :-)user166390
I was suggesting to KISS. And to use Queues to control information [across threads]. Separate the IO layers (async in one thread and/or thread-per-IO) and the processing (one or two centralized threads). I was saying this "is [likely] the wrong approach" while trying to be less blunt about it.user166390
The code you have posted there LOOKS like it could be ok, but it's hard to guarantee that there will be no race conditions or weird sequences of events. One little bug: you're not updating lastUpdate ;) and you'll also want to set 'update' back to false at the end of // do updating... (although you're likely aware of that)mfsiega

1 Answers

2
votes

I think the best way to handle this would be instead of calling p.update(), you could send an asynchronous message to p. This would use the Handler functionality. This is probably the cleanest way, although I believe some (likely trivial) overhead will occur from the message passing.

So, in your ticking thread (i.e. the one that calls the global update), you would have a reference to a Handler object for each client thread. Then, you look would look like

for (Player p : currentPlayers) {
    p.handler().sendMessage(); // this isn't exactly the syntax
}

and in your Player, you would have a PlayerHandler object that extends Handler and overrides handleMessage(Message).

EDIT: the comments on the question are good ones - don't use more threads than you need to. They might seem to be the "right" abstraction, but they introduce a ton of potentially tricky issues. If all of your computation needs to be done in between ticks, it might not matter whether it's done sequentially or not.