Pattern for ensuring a single outstanding task of a given kind
===

Consider the following:

    public class SomeService
    {
        public Task StartAsync()
        {
            return Task.Factory
                .StartNew(() => DoStartup());
        }
        
        public Task StopAsync()
        {
            return Task.Factory
                .StartNew(() => DoShutdown());
        }
    }

The problem with the above is that if multiple calls to either `StartAsync` or `StopAsync` are made then multiple tasks will be created to start/stop the service. Realistically, one would only want a single start/stop task active at any one time. To that end, I usually do something like this:

    public class SomeService
    {
        private readonly object startSync = new object();
        private readonly object stopSync = new object();
        private Task startTask;
        private Task stopTask;
        
        public Task StartAsync()
        {
            var startTaskLocal = this.startTask;
            
            if (startTaskLocal != null)
            {
                return startTaskLocal;
            }
            
            lock (this.startSync)
            {
                if (this.startTask != null)
                {
                    return this.startTask;
                }
                
                this.startTask = Task.Factory
                    .StartNew(() => DoStartup())
                    .Then(x =>
                        {
                            lock (this.stopSync)
                            {
                                this.stopTask = null);
                            }
                        });
                    
                return this.startTask;
            }
        }
        
        public Task StopAsync()
        {
            // similar pattern to above
        }
    }

Now whilst this works, it's kind of ugly. Before I get too far ahead of myself in trying to encapsulate this pattern into something small and reusable, I'm wondering whether there is an already established way of doing so that I am unaware of?

PS. I extend this idea even further by having `StartAsync` wait for any outstanding `StopAsync` call, and vice-versa. That means that only one start OR stop operation can be in progress at any one time. This is pretty easy to do via task composition. If I can first find out whether there's an established way of neatly achieving the above, I can then figure out whether it fits in with this extended behavior.