Steed walking... and deadlocks.

02/04/2011 12:51 -impulse-#1
Has anyone found out how steed walking works?
If so please let me know. I simply can't find out.



For those who have C# sources and have thread/memory usage problems...
Use profilers to see what's your problem...

For big amounts of threads, if you are not using a thread for a player, your problem might be deadlocks. Lately I had about 600 threads at the same time and with dotTrace profiler, I found out that most of them were in a deadlock state as there were no function called on them. Try to keep as few locks as possible.

For those who would like to see such a snapshot here:
[Only registered and activated users can see links. Click Here To Register...]

If anyone got any ideas on how could I get rid of the lock from
Client.Send(packet) I would like to hear their ideas.

Code:
{
byte[] buff = new byte[packet.Length];
Buffer.BlockCopy(packet, 0, buff, 0, packet.Length);
lock(Cryptography)
Cryptography.Encrypt(buff);
Socket.Send(buff);
}
As for memory, my server uses about ... 1.2gb ram after a few hours, though, that's what it should use as I decided not to use collections to handle my items because it would need resizing all the time which would cause lag on the server, and players don't really like it, do they?

My problem now is really the deadlocking. If anyone got any ideas I am here to hear and learn.

Regards,
impulse.
02/04/2011 13:01 Nullable#2
600 threads is an overkill unless you have 600 cores..
As for the locks, you shouldn't deadlock if you do it right; keeping the lock order the same will prevent deadlocking.
Consider:
Code:
function1()
{
    lock(sharedObject1)
    {
       // do something
       lock(sharedObject2)
       {
          // do something else.
       }
    }
}
function2()
{
    lock(sharedObject2)
    {
       // do something
       lock(sharedObject1)
       {
          // do something else.
       }
    }
}
If thread1 acquires the sharedObject1 lock and is about to try to acquire the lock for sharedObject2 while thread2 already has acquired it in function2 and requires lock for sharedObject1; both will be waiting indefinitely for each other to release the objects keeping all the other threads in an idle state as well.

Another way would be using Monitor.TryEnter() with a timeout parameter in order to bail your code out of deadlock situations, try to recover a stable state and continue working.

For the lock around Client.Send(), off the top of my head right now, you might use a small threadpool of worker threads (around 10 threads maybe?) that will take care of sending data by passing your client objects to a queue for processing.
02/04/2011 13:42 -impulse-#3
Quote:
Originally Posted by Nullable View Post
For the lock around Client.Send(), off the top of my head right now, you might use a small threadpool of worker threads (around 10 threads maybe?) that will take care of sending data by passing your client objects to a queue for processing.
Well as you can see in my snapshot, over 600 threads are in a deadlock state at Client.Send()...

I tried with a queue, but it errors....while adding :confused:, as I would have to do a go through the client pool each millisecond to send the packets from the queues, so there wouldn't be lag.

Error: Something about resizing the queue...can't find the file now :S
02/04/2011 14:04 Nullable#4
Again, having 600 threads is an overkill. Each thread wastes CPU time and you said you're polling the pool each millisecond, doing so is probably the reason of deadlocks.

Let alone that each thread uses 1 mb as stack space by default which explains your high memory usage (half of it is because of all these threads).

You might have not synchronized access to the queue correctly.
You can also use an independent queue per thread, and you don't have to poll the queue each time, you can use a notification-style engine that notifies one of the threads available that there is data to process.
02/04/2011 15:17 -impulse-#5
You got me wrong again...

Let me explain to you what I use.
My Client class has a reference to a Screen class.

Each Screen class has it's own System.Threading.Timer timer, for monsters/items so they move/die/dissapear w/e. Because of the deadlocks, when a threading.timer can't use a pooled thread, it makes another one, and so the server gets to have many, many threads. The deadlocks appear in the Client.Send function.

I tried to use a queue so only one thread could send the data. That way there wouldn't be needed a lock for the cryptography.

Now, The way I see it, I'd need a thread to access the queues and see if there is anything queued, and if so it will send the data, but, to keep the players out of lag, I believe I'd have to run that function each ms.
Even if I do lock(client.Queue), some errors appear about adding another packet in the queue, something about resizing or whatever.

I hope you got now what I meant.
02/04/2011 18:40 KraHen#6
I don`t see why you`re locking the crypto object, though I personally create an instance of the crypto for every client.
02/04/2011 19:35 ~Falcon#7
Quote:
Originally Posted by KraHen View Post
I don`t see why you`re locking the crypto object, though I personally create an instance of the crypto for every client.
Multithreaded calls to the send function; if there's two calls at the same time, they could modify the counters, leading to a corrupted packet. The chances are slim though.
02/04/2011 20:55 -impulse-#8
Quote:
Originally Posted by ~Falcon View Post
Multithreaded calls to the send function; if there's two calls at the same time, they could modify the counters, leading to a corrupted packet. The chances are slim though.
And on a populated server, the chances go high...
02/04/2011 21:11 KraHen#9
@impulse : get on yahoo for a second please :D
02/05/2011 00:18 _tao4229_#10
Use System.Threading.ThreadPool properly
02/05/2011 13:00 tanelipe#11
If certain people won't stop the spam, i will start handing out infractions.