I want to thread heavily

  • Thread starter Thread starter jp2msft
  • Start date Start date
J

jp2msft

I am developing a new application.

Since it is being developed from scratch, I want to implement a lot of
threading - especially for my SQL calls.

The problem I noticed is that I can't seem to interact with data that is in
a thread, and all data that goes to a thread must be static - hence my
application can not access it.

Is there a place that spells out how to thread my routines and make it so
that I can pass data to it and read the resulting data that results?

My preferred language is C# or VB, using Visual Studio 2005.

Thanks for the help!
 
jp2msft said:
I am developing a new application.

Since it is being developed from scratch, I want to implement a lot of
threading - especially for my SQL calls.
Threading is not some sort of fairy dust that will make your application
good if you sprinkle lots of it. Threading is never a goal, it's a means, so
starting out with the idea that you want to have "a lot of threading" is
broken to begin with. What you want is the least threading that still meets
your goals, because threading adds complexity.

In particular, if your calls all go to the same database, threading is
unlikely to be of much help, because the database will only have a limited
capacity for processing your requests in parallel. Your average server will
of course have tremendous parallel capacity, but a) you'll have to share it
with everyone else and b) your requests will probably get through *faster*
if you execute them one by one rather than forcing the DB to do them in
parallel.

That's not to say executing DB requests in parallel in a single application
never has any merit, but if your goal is just to increase throughput, it's
probably sufficient to use a limited number (possibly just one) of
asynchronous calls (.BeginExecuteReader() and the like) and leave the rest
to the thread pool.

If you just want to ensure your UI remains response as you're processing
data, using asynchronous calls, BackgroundWorker and/or
ThreadPool.QueueUserWorkItem() should do the trick.
The problem I noticed is that I can't seem to interact with data that is in
a thread, and all data that goes to a thread must be static - hence my
application can not access it.
Where do you get this idea? A thread can access any data that's reachable to
it, and you can start one from any object.

A thread routine is a delegate that has full access to the members of its
declaring class, and on top of that, Thread.Start() and all the asynchronous
method allow you to pass an arbitrary object "state" to store whatever
additional data you require. So:

class A {
int a;

void foo() {
string extraData;
Thread thread = new Thread(threadMethod, extraData);
thread.Start();
}

void threadMethod(object state) {
string extraData = (string) state;
// "a" is accessible here too
}

void bar(SqlCommand c) {
string extraData;
c.BeginExecuteReader(endExecuteReader, c);
}

void endExecuteReader(IAsyncResult ar) {
SqlCommand c = (SqlCommand) ar.AsyncState;
// "a" is accessible here too
using (SqlDataReader r = c.EndExecuteReader(ar)) {
...
}
}
}
Is there a place that spells out how to thread my routines and make it so
that I can pass data to it and read the resulting data that results?
Try googling "asynchronous programming". It's the least bothersome way of
leveraging parallel processing.
 
Thanks Mr. Mostert.

My goal is to keep the UI responsive. Sometimes our connections are broken
in this manufacturing environment, and this causes the App to hang until the
server request times out.

I'll look into the background worker threads.

ThreadPool.QueueUserWorkItem() is something I've never heard of.
 
jp2msft said:
Thanks Mr. Mostert.
Please, either "Jeroen" or "whatsyerface" will do fine.
My goal is to keep the UI responsive. Sometimes our connections are broken
in this manufacturing environment, and this causes the App to hang until the
server request times out.
BackgroundWorker should be good for this, as it was designed for UI
scenarios. In fact, the documentation mentions your very scenario:

"The BackgroundWorker class allows you to run an operation on a separate,
dedicated thread. Time-consuming operations like downloads and database
transactions can cause your user interface (UI) to seem as though it has
stopped responding while they are running. When you want a responsive UI and
you are faced with long delays associated with such operations, the
BackgroundWorker class provides a convenient solution."
ThreadPool.QueueUserWorkItem() is something I've never heard of.
It's quite useful, but also quite specialized -- it's a "fire and forget"
way of doing something in the background, and the threadpool will ensure
these tasks will run with optimal parallelism for the system.

Unfortunately, the "forget" part means you have to implement synchronization
yourself if you want to know if/when the work was done. For most scenarios
asynchronous calls are more appropriate, and for applications with a UI
BackgroundWorker can do the heavy lifting, since it was designed with
progress reporting in mind.
 
Jeroen,

I've found a very through example on the BackgroundWorker Class in the VS
Help, but I have a question that it does not address.

I have at least three (3) different, time-consuming tasks that I'd like to
use the BackgroundWorker Class on. Two are for database queries, and one is
for text validation.

My question is: Can the one BackgroundWorker Class be used for all three (3)
of these tasks? Some of the tasks do, on occasion, call one of the other
tasks.

I see in the BackgroundWorker_DoWork method that there is a "sender" object.
Would the "sender" be the name of the function that I used to call the
BackgroundWorker's RunWorkerAsync method?

Or, should I drop a separate BackgroundWorker component on the form for each
of my time-consuming tasks?

Did this question make sense?
 
jp2msft said:
I've found a very through example on the BackgroundWorker Class in the VS
Help, but I have a question that it does not address.

I have at least three (3) different, time-consuming tasks that I'd like to
use the BackgroundWorker Class on. Two are for database queries, and one is
for text validation.

My question is: Can the one BackgroundWorker Class be used for all three (3)
of these tasks? Some of the tasks do, on occasion, call one of the other
tasks.
If you're already running a task in the background, then there's no point to
having that task start its dependent task in the background separately. I'll
demonstrate what I mean shortly.
I see in the BackgroundWorker_DoWork method that there is a "sender" object.
Would the "sender" be the name of the function that I used to call the
BackgroundWorker's RunWorkerAsync method?
No, "sender" in an event handler is always the object that triggered the
event. You can have multiple BackgroundWorkers share the same event handler,
and "sender" would contain the BackgroundWorker that the event is actually
for. Let's put this aside for a minute.

What you could do is create your own methods that perform whatever
long-running task you need, possibly returning data. Let's say you have this:

DataTable getLotsOfData() { ... }
ValidationResults validateLotsOfText(string lotsOfText) { ... }

Now, when you need to perform one of these tasks from your UI thread, you
can call on a BackgroundWorker. You can create these programmatically or
drag them as components. Let's say you use components, as it's a little
easier. You can do it all in one BackgroundWorker, but this is harder to
program -- it's easier to use separate BackgroundWorkers for separate tasks.
(If you have lots of different tasks that need to run this way, or more than
one instance of the same task, you should create BackgroundWorkers from your
code rather than using design-time components.)

So let's say you have two BackgroundWorker components, one for LotsOfData
and the other for LotsOfText. When you need to start either of these
activities from your UI, you call .RunWorkerAsync() on the appropriate
BackgroundWorker:

GetLotsOfDataBackgroundWorker.RunWorkerAsync();
ValidateLotsOfTextWorker.RunWorkerAsync(lotsOfText);

The event handler for ValidateLotsOfTextWorker might look like this, calling
your method:

private void ValidateLotsOfTextWorker_DoWork(object sender,
DoWorkEventArgs e) {
string lotsOfText = (string) e.Argument;
e.Result = validateLotsOfText(lotsOfText)
}

When this is done, the worker's RunWorkerCompleted event will fire:

private void ValidateLotsOfTextWorker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
// Handle the error
} else {
ValidationResults v = (ValidationResults) e.Result;
// do something with the results
}
}

Now let's say you do the same for LotsOfData, but LotsOfData needs to
validate LotsOfText as part of its operation. Simply call that method
directly from within the DoWork handler:

private void GetLotsOfDataBackgroundWorker_DoWork(object sender,
DoWorkEventArgs e) {
// go to the database and get LotsOfText here
ValidationResults v = validateLotsOfText(lotsOfText);
}

When you want a long-running task done from your UI, use the
BackgroundWorker. If you're already in the background, you don't need to
bother with that and you can simply call methods as you're used to. There's
no need for the *background* task to be responsive, after all.

There's one thing that won't work very well if you do it like this, and
that's progress reporting. If you want your long-running task to report
progress, things get more complicated because you'll want your methods to
call on a BackgroundWorker to do that. But you can't call on just any
BackgroundWorker, because your UI thread might be using it -- you need to
pass the BackgroundWorker to the dependent method. Once you've reached this
point it's probably easier to create BackgroundWorker instances yourself and
not use components. If you don't need to report progress, the above method
will do fine.
 
Back
Top