Search code examples
c#optimizationfire-and-forget

C# Improvement on a Fire-and-Forget


Greetings

I have a program that creates multiples instances of a class, runs the same long-running Update method on all instances and waits for completion. I'm following Kev's approach from this question of adding the Update to ThreadPool.QueueUserWorkItem.

In the main prog., I'm sleeping for a few minutes and checking a Boolean in the last child to see if done

while(!child[child.Length-1].isFinished) {
    Thread.Sleep(...);
}

This solution is working the way I want, but is there a better way to do this? Both for the independent instances and checking if all work is done.

Thanks

UPDATE: There doesn't need to be locking. The different instances each have a different web service url they request from, and do similar work on the response. They're all doing their own thing.


Solution

  • If you know the number of operations that will be performed, use a countdown and an event:

    Activity[] activities = GetActivities();
    int remaining = activities.Length;
    using (ManualResetEvent finishedEvent = new ManualResetEvent(false))
    {
        foreach (Activity activity in activities)
        {
            ThreadPool.QueueUserWorkItem(s =>
            {
                activity.Run();
                if (Interlocked.Decrement(ref remaining) == 0)
                    finishedEvent.Set();
            });
        }
        finishedEvent.WaitOne();
    }
    

    Don't poll for completion. The .NET Framework (and the Windows OS in general) has a number of threading primitives specifically designed to prevent the need for spinlocks, and a polling loop with Sleep is really just a slow spinlock.