Multithreading and Signaling for events like shutdown or exceptions

571 views
Skip to first unread message

robf

unread,
Aug 4, 2013, 10:44:09 PM8/4/13
to topshelf...@googlegroups.com
Hi,

I like the code I see in ConsoleRunHost.cs for catching unhandled exceptions and using ManualResetEvent. Should I create these kinds of waits and signals myself or this part of a service or host control class? Should I launch my own threads? My service is .NET 4.5 so I can choose TPL, ThreadPool.QueueUserWorkItem, etc.
Should I start with foreground threads and flip them to background for special exceptions?

My worker threads are mostly non-blocking so I could poll for volatile flags or something and another ManualResetEvent could wait/join until timeout just in case thread does not die by itself.

Thanks!

Rob F.





Travis Smith

unread,
Aug 5, 2013, 9:53:49 AM8/5/13
to topshelf...@googlegroups.com

If you're TPL, I would just check for a cancel event, and in the shutdown activate the cancel event. 

An example Topshelf service I have has the following in start (with types added)

// load app config stuff
...
(Task)_orphanCleanup = (TaskFactory)_taskFactory.StartNew(DiscoverOrphanedAndAgedMetrics);

Then in shutdown

// signal shutdown
_cancellationTokenSource.Cancel();
// wait up to 5seconds for the action to complete it's current task
_orphanCleanup.Wait(5000);


So my DiscoverOrphanedAndAgedMetrics has a while(!_cancellationTokenSource.IsCancellationRequested) loop. This would be pretty common behaviour for a Topshelf service. Setup a thread and launch it from Start then shut it down from Stop. You can't block in Start, otherwise it will never run as a service. Start has to complete in given period of time otherwise the service control system will kill it. 



-Travis


--
You received this message because you are subscribed to the Google Groups "topshelf-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topshelf-discu...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Chris Patterson

unread,
Aug 5, 2013, 12:54:12 PM8/5/13
to topshelf...@googlegroups.com
Your service should stick to handling Start/Stop, and let Topshelf deal with any exceptional conditions that occur in background threads. If you're using the TPL, fortunately you are immune from the unhandled exception and just have to deal with the exception not observed if you're on 4.0 with the default behavior.

That being said, Start should return as soon as possible, or call the RequestAdditionalTime() method on the HostControl argument to avoid getting killed by the SCM. And your service should START, meaning that the Start method should return and any service related functions be on other threads. For example, using something like MassTransit gives you a separate thread pool for consuming messages, so no additional work here is needed since MT does its own thread management.

Stuart Dunkeld

unread,
Aug 5, 2013, 6:31:34 PM8/5/13
to topshelf...@googlegroups.com
 >> Start should return as soon as possible

I keep getting bitten by this. I've started using TAP style code to avoid it, like this:

public async void Start()
{
    // Because this is async, the Start() method returns immediately and the SCM is happy
    await StartDoingSomething();
}

private Task StartDoingSomething()
{
    return Task.Factory.StartNew(() =>
    {
        // off we go
    }
}

Regards

Stuart 

ps If looks like if you copy text (even a single space) from Visual Studio using Remote Desktop on OSX and paste into a compose window in Gmail, Safari 6.0.5 dies every single time (on my macbook which is running Lion, anyway!)

Travis Smith

unread,
Aug 5, 2013, 6:33:29 PM8/5/13
to topshelf...@googlegroups.com
PS. Use CoRD. Remote Desktop on the Mac is garbage. 


On Monday, August 5, 2013, Stuart Dunkeld wrote:
 >> Start should return as soon as possible

I keep getting bitten by this. I've started using TAP style code to avoid it, like this:

public async void Start()
{
    // Because this is async, the Start() method returns immediately and the SCM is happy
    await StartDoingSomething();
}

private Task StartDoingSomething()
{
    return Task.Factory.StartNew(() =>
    {
        // off we go
    }
}

Regards

Stuart 

ps If looks like if you copy text (even a single space) from Visual Studio using Remote Desktop on OSX and paste into a compose window in Gmail, Safari 6.0.5 dies every single time (on my macbook which is running Lion, anyway!)


On 5 August 2013 17:54, Chris Patterson <ch...@phatboyg.com> wrote:
Your service should stick to handling Start/Stop, and let Topshelf deal with any exceptional conditions that occur in background threads. If you're using the TPL, fortunately you are immune from the unhandled exception and just have to deal with the exception not observed if you're on 4.0 with the default behavior.

That being said, Start should return as soon as possible, or call the RequestAdditionalTime() method on the HostControl argument to avoid getting killed by the SCM. And your service should START, meaning that the Start method should return and any service related functions be on other threads. For example, using something like MassTransit gives you a separate thread pool for consuming messages, so no additional work here is needed since MT does its own thread management.


On Mon, Aug 5, 2013 at 6:53 AM, Travis Smith <tra...@legomaster.net> wrote:

If you're TPL, I would just check for a cancel event, and in the shutdown activate the cancel event. 

An example Topshelf service I have has the following in start (with types added)

// load app config stuff
...
(Task)_orphanCleanup = (TaskFactory)_taskFactory.StartNew(DiscoverOrphanedAndAgedMetrics);



--
-Travis

robf

unread,
Aug 7, 2013, 10:50:13 AM8/7/13
to topshelf...@googlegroups.com
Wow quick responses and great advice! Thanks!!!

Ok I get it. The problem was that I am new to TPL and 4.0 threading constructs. I was missing the CancellationTokenSource signal and the while loop.

Thanks again!

robf

unread,
Aug 7, 2013, 11:30:31 AM8/7/13
to topshelf...@googlegroups.com
Okay this is great information. When you say I should "let Topshelf deal with any exceptional conditions that occur in background threads"  does this include all exceptions? Maybe this does not apply with background threads but only foreground ones? My concern is that a foreground thread might throw an unhandled exception. So should I trap for this or just let it bubble up to topshelf?

As far as start goes, I always start a new thread that actually kickstarts my service. Although I felt a little guilty that this might be cheating. Is this a good practice?

As for MassTransit, I am a huge fan. For production apps this is a great library for me. For now I'm just playing around with sockets and threads to implement some ideas.

Thanks!

robf

unread,
Aug 7, 2013, 11:34:17 AM8/7/13
to topshelf...@googlegroups.com
Thanks Stuart!

asynch and await are new to me. This is very cool!

Chris Patterson

unread,
Aug 7, 2013, 12:21:41 PM8/7/13
to topshelf...@googlegroups.com
Also, I believe that async void is considered poor usage of async by the team (Stephen Toub):


Stuart Dunkeld

unread,
Aug 7, 2013, 1:55:30 PM8/7/13
to topshelf...@googlegroups.com
> On 7 August 2013 17:21, Chris Patterson <ch...@phatboyg.com> wrote:
> Also, I believe that async void is considered poor usage of async by the team (Stephen Toub):

> http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx

Generally, that's true. There are valid use cases for async void other than events, though, like this kind of 'top-level' asynchronous operation.

That linked faq doesn't actually have much to say about the topic, there are some good SO questions on it like http://stackoverflow.com/questions/12144077/async-await-when-to-return-a-task-vs-void and http://stackoverflow.com/questions/8043296/whats-the-difference-between-returning-void-and-returning-a-task

One thing to note carefully is the different handling of exceptions, and the need to handle UnobservedTaskExceptions if your top-level async operation returns a Task.

--stuart
Reply all
Reply to author
Forward
0 new messages