Click here to Skip to main content
15,868,164 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a Windows service that monitors a TCP connection for incoming messages. When a message is received, the message is processed. During the processing, I need to wait 5 seconds before taking some action. For this I intend to implement Timer as below.

I can get many messages coming in through the socket for processing and will get a timer instantiated for each one of those. Does my implementation keep every instance of timer on its own scope? Also, what is the proper way to dispose off the timer (see my implementation)?

C#
private Thread worker;

protected override void OnStart(string[] args)
{
    ...
    worker = new Thread(ListenForStatus);
    worker.Start();
}
private void ListenForStatus()
{
    ...
    client = new TcpClient();
    client.Connect(new IPEndPoint(IPAddress.Parse(IPADDR), PORT));
    using (NetworkStream stream = client.GetStream())
    {
        int numBytesRead = stream.Read(data, 0, data.Length);
            if (numBytesRead > 0)
            {
                ...
                ProcessEvent(stringData);
            }
    }
}

private void ProcessEvent(string Status)
{
    System.Timers.Timer aTimer = new System.Timers.Timer();
    aTimer.Elapsed += (sender, eventArgs) => {
        HandleTimerElapsed(Status);
    };
    aTimer.Interval = 5000;
    aTimer.Enabled = true;
    // Do I dispose the Timer like this?
    aTimer.Stop();
    aTimer.Dispose();
}

private void HandleTimerElapsed(string Status)
{
    // Do something
}


What I have tried:

Please refer to my implementation.
Posted
Updated 21-Feb-22 23:55pm
v2
Comments
_Asif_ 22-Feb-22 3:36am    
why not System.Threading.Thread.Sleep(5000);?
Ashish Singh Feb2022 22-Feb-22 3:41am    
I’m not looking for blocking call. I still need the service to execute instructions in between.

For a windows service, I would be more inclined to use Asynchronous programming, async & await. Here is a mock working example for you, with cancellation built in, that was built as a DotNetCore 6.0 console app:

Job.cs
C#
namespace TaskCompletionSourceDemo;

internal class Job
{
    private TaskCompletionSource<bool>? tcs;

    public Task StartJobAsync(CancellationToken token = default)
    {
        tcs = new TaskCompletionSource<bool>();

        Task task = LongTask(token);

        return tcs.Task;
    }

    private async Task LongTask(CancellationToken token = default)
    {
        await Task.Delay(5000, token).ConfigureAwait(false);

        if (token.IsCancellationRequested)
        {
            tcs!.TrySetCanceled();
            return;
        }

        tcs!.TrySetResult(!token.IsCancellationRequested);
    }
}

Program.cs
C#
using TaskCompletionSourceDemo;

Job job = new();

Console.WriteLine("Before Job!");

CancellationTokenSource cancelSource = new();

Task task = job.StartJobAsync(cancelSource.Token);

while (!task.IsCompleted)
{
    if (Console.KeyAvailable && cancelSource.Token.CanBeCanceled)
    {
        cancelSource.Cancel();
        Console.WriteLine("** Cancelled!");
        break;
    }
}

Console.WriteLine("After Job!");

Hope this helps!
 
Share this answer
 
Comments
Ashish Singh Feb2022 25-Feb-22 2:50am    
Thanks @Graeme_Grant.

If I make the ProcessEvent method an async method ProcessEventAsync, will the method block the execution of the whole program for 30 seconds or just its instance? I would like ListenForStatus() method to call new instance of ProcessEventAsync whenever there is a new TCP stream. Every ProcessEventAsync will await 30 second before "Doing Something"


protected override void OnStart(string[] args)
{
    ...
    worker = new Thread(ListenForStatus);
    worker.Start();
}
private void ListenForStatus()
{
    ...
    client = new TcpClient();
    client.Connect(new IPEndPoint(IPAddress.Parse(IPADDR), PORT));
    using (NetworkStream stream = client.GetStream())
    {
        int numBytesRead = stream.Read(data, 0, data.Length);
            if (numBytesRead > 0)
            {
                ...
                ProcessEventAsync(stringData);
            }
    }
}

private async Task ProcessEventAsync(string Status)
{
    await Task.Delay(TimeSpan.FromSeconds(30));
    // Do something
}
Graeme_Grant 25-Feb-22 7:00am    
I suggest breaking out a side project with just the key parts to test your theories. Once you have a good understanding and working version, then implement it in your main project. The above is exactly that. I do this regularly to test and sometimes compare theories for roadblocks and improve performance with what I am working on.

Also, for a project like yours, I would look at using IWebClienFactory for pooling WebClients. You will see a big performance improvement. The other is to stop using synchronous code with WebClient and move fully to asynchrounous. This will help greatly with reducing thread blocking that you are encountering.
Ashish Singh Feb2022 25-Feb-22 7:10am    
Ok thanks. I’m just looking for some confirmation that async/await will not block tcp stream in the pipeline while processing the one in hand. Also, I need a way to cancel all async tasks if the service is stopped (on stop method) - where would I declare cancel token etc . I’m new to this site so am not particularly familiar with creating projects and such. But I’ll look into it. Thanks for your support though.
Graeme_Grant 25-Feb-22 7:33am    
When you await an asynchronous method call, you will pause on that thread, but the Asynchronous method will continue running in its own thread. That is what my code sample is doing.

If you are not aware of this, then you need to do some research and get yourself up to speed on the mechanics. Here are some videos to get you started:
1. Webcast: Asynchronous Programming Demystified - YouTube[^]
2. Async Best Practices for C# and Visual Basic - YouTube[^]
3. Understanding how to use Task and ValueTask - YouTube[^]
4. C# Async / Await - Make your app more responsive and faster with asynchronous programming - YouTube[^]

And here is a video on the IHttpClientFactory: Resilient HttpClient using Polly and IHttpClientFactory in .NET Core 3 - YouTube[^]
Ashish Singh Feb2022 25-Feb-22 7:44am    
I understand with the await operator, StateMachine is spun up and this is what gives a sense of multi-threading operation. What I don’t understand is if my calling method (ListenForStatus) will continue to process incoming tcp streams while the ProcessEventsAsync awaits on Task.Delay (which apparently spins up a new thread). I think I’m just cutting some slack asking around instead of testing it myself. I’ll check out the videos you posted, thanks again.
Timers are a scarce resource, and shouldn't be created unless necessary. Instead, I'd have one permanently running timer (or more likely a thread) and add information to a "waiting" list to count down. Set the interval to (say) half a second and add a expiry time, then set up the info for what to do when it times out as part of your collection (the Connection and a delegate to call, perhaps) and your code becomes a lot cleaner and more manageable.

The timer or thread checks the current DateTime against the expiry and executes the delegate when it has expired then removes it from the collection. You'll need to be careful of thread safety, but you'd probably have to do that anyway if you are talking about multiple TCP connections as threading is the only sensible way to handle them anyway.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900