0

I have a client-server architecture and I am sending messages from the client to the server every 70ms. On the server side, I want to introduce a simulated network latency. To do this, I have the following:

//Receive incoming messages and put into temp queue.
private void DataReceived(object sender, DataReceivedEventArgs args)
{
    TemporaryRawMessages.Enqueue(args.Bytes);
    args.Recycle();
}

//Runs on separate thread
void ProcessMessages()
{
    while (true)
    {

        if (TemporaryRawMessages.Count > 0)
        {
            var raw = TemporaryRawMessages.Dequeue();
            Task taskA = Task.Factory.StartNew(() => DelayedReceive(raw));
        }

    }
}

//Process the received message
void DelayedReceive(byte[] raw_message)
{
    //wait a bit before deserialising and queueing the message
    while (sw.ElapsedMilliseconds < LatencyUp) { }
    var message = (ClientToServerMessage)Utils.Deserialize(raw_message);
    Messages_In.Enqueue(message);

}

The server receives a message and puts it into a temporary queue. Next, ProcessMessages() picks up any new messages and spawns a new Task. The task waits a bit before putting the message into another queue, which is picked up by the main program.

The problem is that if I time DelayedReceive, I see timings such as: 3, 241, 46, 99,... There is no consistency. Each message should be delayed by 70ms, offset by the network latency up. In other words, all messages are delayed by X (eg 100ms), but are equally spaced apart at 70ms.

Any ideas on what the issue is?

pookie
  • 3,796
  • 6
  • 49
  • 105
  • Why can't you just use Thread.Sleep? – Kind Contributor Feb 19 '18 at 11:35
  • 1
    If your work is synchronous, then `Thread.Sleep(70)`, if asynchronous then `await Task.Delay(70)`. Right now you are doing fire and forget with `Task.Factory.StartNew`. If this is for tests then I would remove that and simply use `Thread.Sleep(70)` – FCin Feb 19 '18 at 11:38

1 Answers1

0

When creating a new Task there is no guarantee that it will be started right away, it is just a promise that the code will be executed at some point in time.

Meaning, that your DelayedReceive method will be called at some point in time. But it does not have to be right away.

The timings can be explained as you are referencing an external variables (sw and LatencyUp) inside the DelayedReceive method. Multiple tasks can reference these values in presumably the wrong order.

See also:

RMH
  • 817
  • 5
  • 13
  • Makes sense. Thanks for the clarification. I had assumed that the task would be started immediately. – pookie Feb 19 '18 at 21:00
  • But if you await `Task.Run`, then it will be scheduled with `ThreadPool.QueueUserWorkItem` instantly, so the difference might be around ~10ms – FCin Feb 20 '18 at 07:38