doing some background work occasionally

B

bonk

I have an application that needs to perform some background work, i.e.
Logging, wich must not block the main thread. How would I basically
design such a scenario? It is obvious that I should do that on an extra
thread but I think it is a bad idea to spawn a new thread everytime a
log-message is written and let it die once the message was written. But
how do I keep a thread alive and trigger the log-messages and pass the
string to that thread? Also, should I give that thread a lower
priority? Maybe there is a best practice for this kind scenario?
 
P

Peter Duniho

bonk said:
[...] But
how do I keep a thread alive and trigger the log-messages and pass the
string to that thread? Also, should I give that thread a lower
priority? Maybe there is a best practice for this kind scenario?

I believe that the .NET worker thread pool will address what you want.

(non-existent newsgroup removed from Newsgroups: field)
 
B

bonk

Thank you for that tip. One questions though:

1. If an exception occurs inside a thread of a queued workitem how can
I rethrow that exception on the main thread?

Peter said:
bonk said:
[...] But
how do I keep a thread alive and trigger the log-messages and pass the
string to that thread? Also, should I give that thread a lower
priority? Maybe there is a best practice for this kind scenario?

I believe that the .NET worker thread pool will address what you want.

(non-existent newsgroup removed from Newsgroups: field)
 
M

Marc Gravell

I would look at a queue, accessed (for instance) via a static/singleton
pattern. Access to the queue would be sync'd. callers would
* lock
* enqueue string
* check count; if ==1 then Monitor.Pulse as have just restarted the Q
* unlock
The (single) logging thread (started in the static/singleton ctor) would
* lock
* check count
* if == 0
* Monitor.Wait
* unlock
* back to the top
* else
* dequeue
* unlock
* log
* back to the top

This way, you have a single thread that stays alive, but doesn't hammer the
CPU while the Q is empty; callers only block to enqueue, not to log.
You might also add something to allow graceful teardown of the thread
(without Thread.Abort), and I'd probably make the logging thread a
background thread anyway...

Marc
 
M

Marc Gravell

That sounds more like an async callback... in which case, create a delegate
to a method, and call BeginInvoke on the delagate, also providing the
callback delegate (to a method e.g. on your form). In the callback, you can
then use the Form's BeginInvoke etc to get back to the UI thread.

Marc
 
P

Peter Duniho

bonk said:
Thank you for that tip. One questions though:

1. If an exception occurs inside a thread of a queued workitem how can
I rethrow that exception on the main thread?

I'm not really sure what that would mean, exactly. Since the exception
doesn't occur on the main thread in that case, and the main thread would be
happily going along executing its own code, at what point would you have the
main thread get interrupted with the exception? How should the main thread
be expected to recover from the exception, given that the exception would
have nothing to do with what the main thread actually was doing?

IMHO, a much better approach would be to come up with some signaling
mechanism that your threads can use to notify the main thread of an error,
and have the main thread check that now and then. Or maybe even better,
have the worker thread, upon catching a thrown exception, use Invoke or
BeginInvoke to run a delegate on the main thread, causing the main thread to
process the error in whatever way you feel is appropriate.

Pete
 
B

bonk

The scenario is this: as soon as any excpetion occurs in one of the
threads the thread will be finished (there is one big try{}catch{}
inside the thread's callback. In case an exception occured the main
thread must be resonsible of handling the excpetion. This is a
requirement by design of the main application.
Or maybe even better,
have the worker thread, upon catching a thrown exception, use Invoke or
BeginInvoke to run a delegate on the main thread, causing the main thread to
process the error in whatever way you feel is appropriate.

This sounds like a good idea for my scenario. I now need to find out
how to run the delegate on the main thread an pass the exception
correctly.
 
R

Robert Ludig

Sorry, I forgot to mention that it a console application. How would I
do it in this case? Invoke a delegate on a main thread from another
thread?
 
P

Peter Duniho

bonk said:
The scenario is this: as soon as any excpetion occurs in one of the
threads the thread will be finished (there is one big try{}catch{}
inside the thread's callback. In case an exception occured the main
thread must be resonsible of handling the excpetion.

But what do you mean by "handle the exception"?

Typically, that phrase is used to describe the use of try/catch/finally to
provide a point at which the code can recover from the exception. But that
only will occur on the thread on which the exception occurred.

I suppose you could devise some way to duplicate the specifics of the
exception thrown, and then provide a bottleneck on the main thread where you
throw the duplicate. But I don't see the point in doing that, since all the
main thread will (presumably) do at that point is run some error-handling
code and continue normally. In that case, it makes more sense for the main
thread to simply run the error-handling code and be done with it, rather
than trying to emulate in the main thread an exception that happened on a
different thread.
[...]
Or maybe even better,
have the worker thread, upon catching a thrown exception, use Invoke or
BeginInvoke to run a delegate on the main thread, causing the main thread
to
process the error in whatever way you feel is appropriate.

This sounds like a good idea for my scenario. I now need to find out
how to run the delegate on the main thread an pass the exception
correctly.

IMHO, what you really want to know is how to extract the information that
you need from the exception, and pass *that* to the main thread. That said,
I suppose you could pass the exception itself. I'm just not sure what the
point of that would be, and it could tempt you into trying to rethrow the
exception on the main thread, which I think would be a mistake.

As Jon said, you can use Invoke or BeginInvoke to execute the delegate on
the main thread. You write that you have a console application, but that
doesn't preclude having a message pump. So one option is to go ahead and
run a message pump in your console application.

If that's not a suitable solution for you, then it seems to me you could
easily emulate the BeginInvoke behavior by creating a queue into which you
place your own "events" to be handled, and from which the main thread
retrieves for processing. Of course, by doing that you'd basically be
reinventing the wheel, and I'd think you'd be better off just putting a
message pump in your console application. But you could do it that way.

Pete
 
S

ssamuel

Peter said:
But what do you mean by "handle the exception"?

Typically, that phrase is used to describe the use of try/catch/finally to
provide a point at which the code can recover from the exception. But that
only will occur on the thread on which the exception occurred.

I suppose you could devise some way to duplicate the specifics of the
exception thrown, and then provide a bottleneck on the main thread where you
throw the duplicate. But I don't see the point in doing that, since all the
main thread will (presumably) do at that point is run some error-handling
code and continue normally. In that case, it makes more sense for the main
thread to simply run the error-handling code and be done with it, rather
than trying to emulate in the main thread an exception that happened on a
different thread.

To elaborate and add some friendly amendments, exceptions come in
different flavors:

If your exception is, "some resource that I expected isn't available,"
the main thread may be able to fix that by restarting the resource and
re-spawning the background process. This requires that the main thread
know how to and be capable of restarting failed processes.

If the exception is, "the user gave me some data to process that has
errors," the main thread -- a UI thread, probably -- would be the only
one who could fix it, generally by informing the user that their data
doesn't compute and asking them to retry. This requires saving user
input and letting the user modify it and resend.

If the exception is, "something I didn't expect happened," chances are,
no one's going to be able to fix that. It should bubble up, therefore
being caught at the thread boundary and possibly rethrown (you're
right: it's dangerous to just rethrow, but also sometimes appropriate)
or repackaged and thrown upwards. A good example of this is running out
of memory or disk space. Rarely can you do more than tell the user what
happened.

This is part of the reason one should avoid catching Exception.
Instead, it's better to catch specific exceptions and know what each
one means. On a background thread boundary, however, it's often useful
to catch Exception after everything else, just in case something slips
through, so it's not lost in ether.

On the other hand, if you're not going to do anything other than kill
the background process if there's an exception, you might as well not
catch it. Don't catch anything you're not going to use, and never do
the following:

try { ... }
catch { throw; }

That's nothing more than a waste of the overhead of a try/catch block.
If nothing else, put some diagnostic information somewhere so that
someone who knows what they're doing can inspect it and deduce what
happened.


Stephan
 
B

Brian Gideon

bonk,

The best way to do this is by using a special kind of queue. Marc
already touched on this, but let me explain some more. This queue's
Dequeue method will block when it's empty. This is known as a blocking
queue. It is notoriously difficult to implement. I've seen more
failed attempts at this than I can count. But, once you have it
everything else is pretty easy.

Basically, you'll create a dedicated logger thread. That thread will
spin around in an infinite loop calling the queue's Dequeue method.
Remember, the Dequeue method will block when empty so most of the time
the thread will be idle. When an item appears the Dequeue method will
return and you can process the returned object accordingly and then
call Dequeue again.

All of the other threads in your application will be enqueueing the log
message contents into the queue.

If you choose to use this approach then I highly recommend you model
your queue off of Jon's producer-consumer example. Producing is the
same as enqueueing and consuming is the same as dequeueing so it should
be pretty easy if you follow his example exactly.

(Look for the ProducerConsumer class)
http://www.yoda.arachsys.com/csharp/threads/deadlocks.shtml

Brian
 
B

bonk

Thank you for the detailed replies. Just to make things more clear, all
I actually wanted to do is, in case in one of the backround threads
occurs an excpetion I want to terminate that thread and the main thread
(it has to be the main thread that does that) needs to write details of
the exception to a logstream. What would be a good approach to
implement this. Is introducing the afore mentioned messagepump the
best/only option I have?

Peter said:
bonk said:
The scenario is this: as soon as any excpetion occurs in one of the
threads the thread will be finished (there is one big try{}catch{}
inside the thread's callback. In case an exception occured the main
thread must be resonsible of handling the excpetion.

But what do you mean by "handle the exception"?

Typically, that phrase is used to describe the use of try/catch/finally to
provide a point at which the code can recover from the exception. But that
only will occur on the thread on which the exception occurred.

I suppose you could devise some way to duplicate the specifics of the
exception thrown, and then provide a bottleneck on the main thread where you
throw the duplicate. But I don't see the point in doing that, since all the
main thread will (presumably) do at that point is run some error-handling
code and continue normally. In that case, it makes more sense for the main
thread to simply run the error-handling code and be done with it, rather
than trying to emulate in the main thread an exception that happened on a
different thread.
[...]
Or maybe even better,
have the worker thread, upon catching a thrown exception, use Invoke or
BeginInvoke to run a delegate on the main thread, causing the main thread
to
process the error in whatever way you feel is appropriate.

This sounds like a good idea for my scenario. I now need to find out
how to run the delegate on the main thread an pass the exception
correctly.

IMHO, what you really want to know is how to extract the information that
you need from the exception, and pass *that* to the main thread. That said,
I suppose you could pass the exception itself. I'm just not sure what the
point of that would be, and it could tempt you into trying to rethrow the
exception on the main thread, which I think would be a mistake.

As Jon said, you can use Invoke or BeginInvoke to execute the delegate on
the main thread. You write that you have a console application, but that
doesn't preclude having a message pump. So one option is to go ahead and
run a message pump in your console application.

If that's not a suitable solution for you, then it seems to me you could
easily emulate the BeginInvoke behavior by creating a queue into which you
place your own "events" to be handled, and from which the main thread
retrieves for processing. Of course, by doing that you'd basically be
reinventing the wheel, and I'd think you'd be better off just putting a
message pump in your console application. But you could do it that way.

Pete
 
P

Peter Duniho

bonk said:
Thank you for the detailed replies. Just to make things more clear, all
I actually wanted to do is, in case in one of the backround threads
occurs an excpetion I want to terminate that thread and the main thread
(it has to be the main thread that does that) needs to write details of
the exception to a logstream. What would be a good approach to
implement this. Is introducing the afore mentioned messagepump the
best/only option I have?

Using the worker thread pool, you don't really terminate the thread so much
as you simply stop doing work on it. That part is easy...just make sure you
have an exception handler in the worker method itself, where you can catch
the exception and exit the method if one occurs.

As far as notifying the main thread of that, you can use any of the methods
suggested here already. Since what you *really* want is simply to have some
data written to a logfile, you could just create a data queue to which the
worker threads write if an exception occurs (before exiting their worker
method, of course), and from which the main thread reads for the purpose of
generating your log file. It's probably not necessary to get so complicated
as creating delegates and invoking them on the main thread.

Pete
 
J

jcreasy

Brian:

A thread queue would fit the specific needs here, but it would take
more work and I wonder if it gives any advantages to the ThreadPool
approach. A dedicated thread for background processing I have found to
only be efficient enough for use when there are enough tasks to keep
the thread busy.

If instead you have a handful of short and quick tasks to accomplish
that are all relatively the same thing, it seems to me that the
ThreadPool makes more sense (not to mention most of the code is already
in place). This after all is why the ThreadPool was put into .NET.

Please let me know if I am missing something or making an incorrect
assumption about your approach.
 
B

Brian Gideon

jcreasy said:
Brian:

A thread queue would fit the specific needs here, but it would take
more work and I wonder if it gives any advantages to the ThreadPool
approach. A dedicated thread for background processing I have found to
only be efficient enough for use when there are enough tasks to keep
the thread busy.

If instead you have a handful of short and quick tasks to accomplish
that are all relatively the same thing, it seems to me that the
ThreadPool makes more sense (not to mention most of the code is already
in place). This after all is why the ThreadPool was put into .NET.

Please let me know if I am missing something or making an incorrect
assumption about your approach.

Typically I would I agree with you. The problem I see with the
ThreadPool is that the order the log messages are processed would be
nondeterministric because it's using multiple threads. It's usually a
requirement to process log messages serially instead of concurrently so
that they get written to a file (or whatever) in time order.

Brian
 
B

Brian Gideon

Peter said:
bonk said:
[...] But
how do I keep a thread alive and trigger the log-messages and pass the
string to that thread? Also, should I give that thread a lower
priority? Maybe there is a best practice for this kind scenario?

I believe that the .NET worker thread pool will address what you want.

(non-existent newsgroup removed from Newsgroups: field)

Peter,

In this case I don't think the ThreadPool will work because it will
process the log messages concurrently. There's no guarentee that they
will be recorded to the storage media in the order they were queued.
That's typically a fundamental requirement for any logging component.

Brian
 
P

Peter Duniho

Brian Gideon said:
In this case I don't think the ThreadPool will work because it will
process the log messages concurrently. There's no guarentee that they
will be recorded to the storage media in the order they were queued.
That's typically a fundamental requirement for any logging component.

Please read the whole thread. My response was in answer to the question of
"how do I keep a thread alive". The original poster was clearly mostly
concerned with how to avoid creating a new thread over and over again, and
that was the point of suggesting the thread pool.

As far as ordering the logs, as I've pointed out elsewhere, my suggestion is
not to actually output the logged data from the worker thread, but rather to
queue the data in a shared location so that the main thread can write the
logged data out.

Nevertheless, the fact is that as long as the work is being done amongst
multiple threads, it is impossible to ensure that data logging happens
sequentially, whether the actual output is done from each thread, or
delegated to some other single thread. The only practical way to ensure
that the logged data is in order is to time-stamp the data so that whatever
component writes the data out can make sure it is written in the correct
order, and even using that method, there exists a theoretical possibility
that unless ALL of the logged data is sorted based on the timestamp once ALL
of the processing is done, that the logged data will still be out of order.

Otherwise, no matter the logging mechanism, there is always the chance that
just before one thread tries to log some data, another thread will be given
its timeslice, generate an event (error), and log that event before the
first thread gets a chance to run again.

The question of how to ensure that the logged data is in order is completely
independent of the question of what thread mechanism is used. As long as
*any* thread mechanism is used, out-of-order data logging is a problem.
Using the thread pool doesn't make this better of course, but nor does it
make it worse, as compared to any other way of running tasks on a thread.

Pete
 
P

Peter Duniho

Brian Gideon said:
[...]
Basically, you'll create a dedicated logger thread. That thread will
spin around in an infinite loop calling the queue's Dequeue method.
Remember, the Dequeue method will block when empty so most of the time
the thread will be idle. When an item appears the Dequeue method will
return and you can process the returned object accordingly and then
call Dequeue again.

All of the other threads in your application will be enqueueing the log
message contents into the queue.

You appear to be suggesting to simply use a queue for the logging itself.
However, you haven't suggested any mechanism by which the queue itself will
be guaranteed to be in order.

Now, it happens that the original poster never suggested that the logged
messages need to be in exactly the same order in which they occurred. It
seems likely that if he's dealing with multiple concurrent tasks that are
not otherwise synchronized with each other, then it doesn't really matter
whether the logged output from those tasks is ordered as well.

*But*...if ordering the logged messages *is* important, as you seem to be
assuming, then simply implementing a queue for the logging doesn't resolve
the out-of-order issue. It just moves it from the i/o part of the code to
the queueing part of the code.

Queueing the *work* itself in a single thread would resolve the ordering
issue with the logged data (as would timestamping the data, as long as it's
sorted once all processing is done), but a) the original poster hasn't
suggested that the logged data needs to be in order, and b) the original
poster hasn't suggested that it's suitable for each work item to be done
serially (he may prefer that a relatively shorter work item started after a
longer one be allowed to run concurrently, so it can complete before the
longer one does).

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top