ProgrammerMan
ProgrammerMan

Reputation: 11

Race Condition: Kryo keeps attempting to serialize items with references

I'm writing a video game utilizing a procedurally generated universe using KryoNet.

A bit of context, KryoNet will serialize the object, and then every reference in the object along with it and try to send that to the other end of the connection, and if it finds something it can't serialize it throws an error.

Right now I'm attempting the multiplayer portion of the game, and I'm running into a problem with race conditions where one thread modifies by adding an object to a collection with references, for example it adds an object with references on one thread between when I compress the object and send it through the network, thus it serializes the entire object graph, when it's supposed to find a corresponding ID on the client after it receives the object, find the object with the ID I got on the server, and reconstitute the reference when it reaches the other end of the connection.

Example:

public class Fleet()
{
...
List shipList;
...
public void SendToClient()
{
    for (Ship ship : shipList)
    {
    this.DoNotModify = true;
    ship.compress();   //Function that removes all class references from it and assigns an object specific ID
    for (int i=0;i<MultiplayerController.clients.size();i++)
    clients.get(i).connection.sendTCP(object);
    ship.decompress(); //Reassign class references from ID's by looking them up from a HashMap
    this.DoNotModify = false;
    }
}

public void AddShip(Ship ship)
{
    if (!this.DoNotModify)
    {
    ...
    //execute time expensive code
    ...
    shipList.add(ship);
    }
}

}

This is psuedo code, but what ends up happening is between it calls ship.compress() and connection.SendTCP() it calls shipList.add() on another thread which adds a ship with something like a reference to an entire planet, and the planet has a reference to other armies, and so forth and it sends the entire object graph. Or it goes through the object graph and tries to send an object that won't serialize and it just blows up with an KryoNetException.

So I'm trying to figure out what to do about this but since I can't add a flag that will check to see if it's being modified between the two method calls inevitably after a few player turns in the game it just blows up and haven't found a solution. There's probably some simple means of fixing this race condition, but using the "synchronized" keyword won't work here as they're separate method calls. Creating my own locks here isn't working either as it runs the two functions simultaneously on separate threads, and after checking the boolean it runs through the function, attempts to remove references and then tries to serialize a bunch of shit that it shouldn't.

I've thought about creating even a sort of queue which will serialize things whenever a thread is on the Thread.Sleep() or something, but that would be a whole pain in the ass that I don't want to create a whole subsystem for.

Thoughts? I'm at a loss here. If there's a simple fix please tell me, I'm all ears.

Upvotes: 1

Views: 102

Answers (1)

prembhaskal
prembhaskal

Reputation: 425

You can make ship.compress to return a new ship (like a clone) with all references removed and use that instead of the actual ship reference. This will also mean that you won't have to decompress

compressedShip = ship.compress(); // return a clone with removed references

by the way, method synchronization works for multiple methods of same object. it is there for syncing between 2 or more separate method calls. https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Upvotes: 0

Related Questions