PolosatiyVjih
PolosatiyVjih

Reputation: 279

C# Deadlock in Named Pipe

Im stuck. I have joined the project that uses Named Pipes, and have lets say "not ideal architecture". And seems like I accidentally received a deadlock:(

The logic is following. There is Named Pipe. Client and Server model. On server part there is a loop, that always pings named pipe and process what client sends, sometimes sending back responses.

On Client side of my pipe, I have following method, from other developer, that is being used to send request to server and receive and return the response.

private object locker = new Object();
private string ListenOnce(string msg)
{
    Debug.WriteLine("Will listen for message " + msg);

    string msgFrom = "";
    if (run) {
        string toReturn = "";
        lock (locker) {

            sw.WriteLine(msg); //Writing command to the pipes
            stream.WaitForPipeDrain(); //Waiting for another process to read the command
            msgFrom = sr.ReadLine(); //Reading
            toReturn = sr.ReadLine ();

            if (toReturn.Contains('¥'))
            {
                string[] split = toReturn.Split('¥');

                if (split.Length > 1)
                {
                    var roomNames = this.connection.application.GameCache.GetRoomNames();
                    for (int i = 1; i < split.Length; i++)
                    {
                        string[] split2 = split[i].Split('¶');
                        if (split2.Length > 1)
                        {
                            string accountName = split2[0];
                            int offenderActorID = int.Parse(split2[1]);
                            string offenderRoomName = split2[2];

                            foreach (var roomName in roomNames)
                            {
                                Room room;
                                if (this.connection.application.GameCache.TryGetRoomWithoutReference(roomName, out room))
                                {
                                    Game game = room as Game;

                                    if (game != null && game.Name == offenderRoomName)
                                    {

                                        GameClientPeer peer = (GameClientPeer)game.ActorsManager.ActorsGetActorByNumber(offenderActorID).Peer;

                                        if (peer != null)
                                        {
                                            peer.KickPlayer();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (toReturn.Contains('¥'))
        {
            return toReturn.Split('¥')[0];
        }
        else
        {
            return toReturn;
        }
    }
    return "";
}

The problem is - in some cases I cant receive response from pipe right when requested, and need to start what I called here "poller". This is a task, that loops 5 times, and during those 5 times "polls" the pipe through this ListenOnce method.

    private void PollTargets()
    {
        timer.Dispose();
        Debug.WriteLine("Going to start polling");
        Task.Factory.StartNew(() => {
            int runCount = 0;
            while (true)
            {
                runCount++;
                PipeOperation request = new PipeOperation(Consts.Pipes.RequestTargets, uniqueID);
                string responseStr = unityConnection.client.SendMessage(JsonConvert.SerializeObject(request));
                Debug.WriteLine("Task is running, response is " + responseStr);

                if (!string.IsNullOrEmpty(responseStr))
                {
                    try
                    {
                        PipeOperation pipeResponse = JsonConvert.DeserializeObject<PipeOperation>(responseStr);
                        if (!string.IsNullOrEmpty(pipeResponse.Payload))
                        {
                            GrenadeExplosionData explosionData = JsonConvert.DeserializeObject<GrenadeExplosionData>(pipeResponse.Payload);
                            if (explosionData != null)
                            {
                                //probably need to invoke that in main thread
                                DealDamage(explosionData);
                                //isRunning = false;
                                Debug.WriteLine("Received nice response, will damage targets");
                                break;
                            }
                        }
                    }
                    catch (Exception exc)
                    {
                        Debug.WriteLine("Something went wrong while polling...");
                        Debug.WriteLine(exc.Message);
                        break;
                    }
                }

                if (runCount > 5)
                {
                    Debug.WriteLine("run count exceed " + runCount.ToString());
                    break;
                }
            }
            RemoveGrenadeFromUnityConnection();
        });
    }

I am starting poller when the Grenade explodes, from timer like that:

        timer = new System.Threading.Timer((obj) =>
        {
            PollTargets();
        },
            null, 4000, System.Threading.Timeout.Infinite); 

And thats it. After people play 2-3 hrs. Seems like I receive a deadlock. It should be taken into account that there might be many grenades on server who starts that poller, so probably it just goes mad at some point over there. Pls help, Im stuck with that. Who has ideas? We should keep in mind, that

        sw.WriteLine(msg); //Writing command to the pipes
        stream.WaitForPipeDrain();
        msgFrom = sr.ReadLine(); //Reading
        toReturn = sr.ReadLine ();

should be used only by one thread at a time, as stream might be read only from one source.

There are several calls to ListenOnce from the code, but not a lot. One is being fired every 4 minutes.The rest ones are not constant, but conditional.

Hope somebody would see where is a mistake here...

Upvotes: 1

Views: 862

Answers (1)

PolosatiyVjih
PolosatiyVjih

Reputation: 279

Found what locks everything...However, it does not help a lot:) Its stream.WaitForPipeDrain();

it tries to read another end of pipe, but because of there is no timeouts in message mode, it just hangs for ever..

Upvotes: 1

Related Questions