Newbie here .... thanks in advance for your patience.
I'm working w/ C# Visual Studio 2005
I've read up on all the comments about problems w/ aborting and suspending/resuming threads. Lots of things to consider. Looks kinda ugly on all fronts. Note that I'm not thinking of using suspend and resume to synchronize threads. I would like to just pause and then restart a particular thread from where it left off. Worst case is to abort the thread.
I'm not using a ThreadPool. This is because some of my operations may take a long time (long running database access routines), may require different priorities, etc. Hopefully this is the right choice. Maybe I should use one
Here's what I'm trying to accomplish. I'll try to use the correct terms, etc:
1. I have an array named myWorkList[]. This contains five Strings such as "Mow The Lawn", "Wash The Car", "Fix The Dog", etc.
2. The Cat looks at the GUI and presses the big green button.
3. This kicks off a loop that executes 5 times. Here's the code:
for (int i = 0; i < 5; i++){
DBMSThreadMgr dbmsThread = new DBMSThreadMgr(); Thread dbmsThreadID = new Thread(new ThreadStart(dbmsThread.DBMSThread)); dbmsThreadID.Name = myWorkList
;
dbmsThreadID.Start();
}
Remarkably (to me anyway) this kicks off five separate threads. The threads are all based on the same object -- DBMSThreadMgr, running the same delegate dbmsThread.DBMSThread.
Each of the five threads has its own name supplied from myWorkList and a unique GetHashCode() value. When you're in the DBMSThread code you can see these values for the current thread with:
Thread dbmsThread = Thread.CurrentThread;
Etc.
Based on the specific name of the thread, I'll take the appropriate action, such as Mow The Lawn.
4. OK, so now back in Main, the Dog protests and presses the big red button. He wants to preferably suspend or worst case abort the "Fix The Dog" thread. Not the other ones ... just "Fix The Dog."
So, what's the recommended solution here It seems like the Thread.Suspend and Thread.Abort are not too popular. And I don't think the Thread.Abort overload which allows an object name would enable me to narrow down to just the "Fix The Dog" thread, especially if the request is coming from Main.
I'm also trying to avoid having specific named thread objects such as FixTheDog, WashTheCar, etc. as the work list will change all the time. I won't know in advance how many threads I'll need for a given exeuction.
I was thinking that perhaps I could set a global signal flag of some type ... which my thread code could check during each pass ... where if the thread's name is "Fix The Dog" and the flag for "Fix The Dog" is set to "abort" or "suspend" I could execute inside my thread code:
Thread.CurrentThread.Abort or
Thread.CurrentThread.Suspend
This seems like a brute force method, and I'm sure there's something a lot more sophisticated I should be using.
Of course, the other problem is that once suspended (or aborted) the Cat wants to press the big green button and restart this thread again. GAK!
Any suggestions or leads on documentation I need to read
Thanks so much!

Aborting and Managing Threads: The Dog or the Cat?
Malar
Good news!
I've been able to use the WaitOne and ManualResetEvent suggestions to pause and restart my thread! A great suggestion.
Now ... if I do in fact want to permanently terminate my thread ... I didn't quite see that one in your example.
From the docs (and I may have this wrong) it seems that the concern with using the Thread.Abort() routine is that you never know the section of code your thread may be running. Hence you could be in a critical section and aborting in the middle might leave you in a bad state.
Would something like this work:
... in my thread code ...
while (1==1)
{
// First thing is to look for a WaitOne. Block here if this manual event is reset
m_evtPause.WaitOne();
// Now start doing all the critical stuff where you don't want to abort in the middle ...
blah blah blah;
} // While Loop
... OK, and in Main ...
1. I do a Suspend on the thread, which blocks the thread at the (I'm assuming) safe WaitOne spot in the code.
2. I do an Abort on the thread, knowing I'm not in a critical code location
3. I do a Join and life goes on...
Is this roughly correct
Thanks again for your patience!
DB
D_a_v_i_d_B
I'm still here. I haven't been combing the forums much because DDJ accepted my article proposal on how to implement threading with support for pause/resume, termination, UI interaction, etc. Been spending some time writing the article and a framewok.
In regards to Item 2 first, you only need to create a single class type to wrap all your work. Then instantiate a separate class for each thread. Therefore you can dynamically create as many threads as you need each using its own instance of a single class. A class is simply a type definition so you'll want to reuse it whereever you can. If each of your classes does something completely different, or even significantly different, then create separate class definitions for each one. Any shared info should go into a base class like so:
class BaseThreadClass
{
//Common stuff
}
class CalcTempThreadClass : BaseThreadClass
{
//Temp specific stuff
}
class CalcAreaThreadClass : BaseThreadClass
{
//Area specific stuff
}
Of course you only need a base class if there is common stuff. If your base class is empty then don't bother using it.
In regards to item 3 your initialization should probably happen prior to starting the thread. To pass data between the application and the thread you should use class variables on the thread class (CalcTempThreadClass). That's why I recommend that you create a class for your threading operation because then you can set the class properties and then invoke a class method. Although you can use a static method for a thread routine it is far more difficult to pass data to it unless you are using shared memory.
In your example of converting between F and C I probably wouldn't use threading at all. The calculation is faster than the overhead of the thread. Even if you had to fetch data from the DB to calculate the value I'd recommend caching it (you probably are anyway). Then provide a method on the class that returns it as F or C like so:
class CalcTemp
{
void ThreadWork ( )
{
//Get data from DB
//Store in field as F
}
public double TemperatureAsF { get { return field; } }
public double TemperatureAsC { get { return FToC(field); } }
}
In this case there is no benefit in using a secondary thread to do such a simple calculation. Events also have a high overhead so unless your controlling a thread's execution I would avoid using events to signal anything. Simple boolean flags work well.
I would not under any circumstances read/write variables in your main program from within your thread. Instead have the thread class expose the variables as properties and have your main program (and/or UI) use the properties from the thread class. This requires that the main program keep the thread class as a field but it is better than littering it with fields. Remember the goal of a class definition is to combine a bunch of related properties and methods into a single, coherent block so if you find that you have a block of variables that are related then you should start thinking about a structure or class.
Finally, item 1. You are correct that a single instance of a class can be used by multiple threads. This is, in fact, what happens with static classes. However every field that can be written to must be synchronized. If your entire class is composed of writable fields then your synchronization will outweigh the benefits of threading because you will, in effect, serialize access. Note that the ReaderWriterLock is your friend if you have fields that are read a lot but seldom written. I personally use this class more than any other sync object. A close second is a simple object variable that I use lock on when reading/writing are about even. Monitors, mutexes, semaphores, critical sections, etc. are great but they aren't as useful. The critical thing about sync objects is that you should only hold on to the lock for as little time as possible. Set the value and get out. If you need to do some calculations or update other fields then try to do this outside the lock. The second important thing about locks is to avoid them in the first place. Many people will get a lock and then do some work if a certain condition is met. Example, delay-initialization of variables which I use all the time:
class Foo
{
private ArrayList m_Arr;
private object m_lckArr = new object();
public ArrayList Properties
{
get
{
lock(m_lckArr)
{
if (m_Arr == null)
m_Arr = new ArrayList();
};
return m_Arr;
}
}
}
This is inefficient because in general the field is already initialized so everybody takes the hit for locking. By using double checks we gain the benefit of synchronization without the overhead (in the general case)
public ArrayList Properties
{
if (m_Arr == null)
{
lock(m_lckArr)
{
if (m_Arr == null) //Check again, overhead compared to lock is low
m_Arr = new ArrayList();
};
};
return m_Arr;
}
Of course in the case of simple object (and integer assignment) then you should use the Interlocked class instead. But that is off topic.
You should avoid sharing classes across threads. Each thread should probably have its own instance of your class. Then you can avoid the sync issue. Given your sample code so far I'm not sure that I'd be using threads in this manner. You seem to create a thread, do some work, and then stall the thread until it is time to do more work. If your threads are going to be sleeping a lot then you may be better off just creating the thread and doing the work on demand instead of trying to keep the thread around all the time. This would reduce the working set of your app with a slight increase in the time it takes to perform your threaded work. A ThreadPool-style implementation like you have now is only good if you expect to be using threads a lot.
As I mentioned earlier one of the golden rules of sync objects is to do as little as possible to avoid locking for too long. In your case of DB requests I'd recommend that you create the variables you need for the request (connection, command, etc.) and execute the command. If you need shared fields to initialize the request then get the lock long enough to initialize the request and then release the lock. If you need to store information in shared fields then lock the object after the DB request comes back. A common technique that I use is to do as much as possible with local variables and then flush changes to shared fields in a single block like so:
void Foo ( )
{
//Set up DB request
//Invoke sproc
//Store results in temporary variable (if appropriate)
local = ...;
//Update shared fields
lock(...)
{
m_Shared = local;
}
}
This is especially useful when dealing with collections of objects or objects that have many properties to set. This doesn't work in all cases but the nice thing about it is that the lock is held for as short a period as time (using Interlocked we can get it even smaller), avoid locking until absolutely necessary and keeps the original object in a consistent state until it is updated.
As a final comment on item 1 it is a great misconception that a multi-threaded app runs faster. This is not true. A multi-threaded app runs slower due to the overhead in thread switching. Multi-threaded apps give the illusion of running faster because the user is not stuck waiting on something from occuring. Therefore you should not use threading to speed up your app because it won't. Use threading when a lengthy operation is needed but you don't want to stall your app. For example even though loading a project in VS is lengthy it is not done on a secondary thread (probably) because until the project loads the user can't do anything anyway. However compilation (which the user may want to cancel) is done on a secondary thread.
In regards to your code example you should remove the Thread.Sleep(1) line. You are assuming here that this will cause your thread to release the rest of its time and let other threads run and this is, in fact, what will happen. However right after you call MyThreads.Start() it is possible that your secondary thread is already running so calling Thread.Sleep(1) may stall your primary thread for no reason. Let Windows deal with threading order. If you really want to control the precedence of threads then use the thread priority but this isn't normally needed.
Michael Taylor - 12/22/05
Bassie
The world still awaits a true Net 2 (suspend depreciated) simple multithreaded example that can be "stopped"(suspend) and "started"(resume). Not the Sleep(1000) or progressbar of yesteryear type. With an explanation of Autoreset, ManualReset, WaitOne, SpinWait , BeginInvoke etc.
It just has not been done.
A "real" code sample that suspends a thread (without an endless loop-,if possible)
while(true)
blah myThread
gotdotnet....which I consider the best forum on c#, still has a 2003 threaded "base" where Suspend(), Resume() are still hot topics.
Come on gurus...
I can come up with code that will do this, but I never know if it's the most "elegant" way to acomplish the task.
How about an example, say 2 buttons and a textbox.
Update the texbox from another thread...with the posibility to "pause" the update.
Taylor...thanks for your help in this thread!
This could become the million hit thread on threads.
Hubajube
My goodness! Michael what a wonderful response! I cannot thank you enough for providing this much detail, and in such a timely manner. i've been trying to piece together "the big picture" on this. This information is something a new guy like me can understand.
Let me take some time to digest this information and think it all through. I may respond back to this thread with an additional question or two, so I'll keep it "open" before I press the "Answered" button.
I've now had at least four responses like yours on various topics via my MSDN subscription. The subscription has paid for itself time and time again. What a great bargain!
While the Cat is now frustrated, the Dog thanks you too!
More to come....
Doug
patjed
I would stick with Thread if you need to control thread priority or need to pause/resume threads. Pausing and resuming threads in the ThreadPool would negatively impact performance.
As for pausing and resuming a thread you should look at the new article Pausing and Resuming Threads in MSDN (http://msdn2.microsoft.com/en-us/library/tttdef8x.aspx). Thread.Suspend and Thread.Resume have been obsoleted in 2.0. I do see a couple of potential problems with your implementation. The first problem I see is that you create a thread for each work item. Do you need them to execute in parallel If so then using a separate thread for each is reasonable but you should be concerned with the fact that performance will be negatively impacted. Even on a dual processor machine running 5 threads is going to cause a lot of thread transitions. If you later add more tasks then the thread count is going to go up. I would instead recommend that you create a custom thread pool class that allocates up to a fixed number of threads based on the workload and the # of processors available. Each work item goes into a queue. The thread pool class pops work items off the list as threads become available. This is sort of how the real ThreadPool works. The # of threads/processor could actually be a configuration file setting and helps to manage the performance.
The second problem that I see is using the thread name to map it to the work to be done. This may cause problems with maintenance and also negatively impacts performance. Ultimately the thread is simply going to invoke a method to do the work (you probably have switch statement that does it now). I'd just pass the appropriate method to the thread instead of using a string name. Then when the thread starts it can simply invoke the method. If you do need to pass additional information about the item then create a custom class (WorkItem) that contains the information and also the thread entry-point routine. Create a custom WorkItem for each work item and then implement the thread entry-point routine as appropriate. Like so,
public abstract class WorkItem
{
private ManualResetEvent m_evtPause = new ManualResetEvent(true);
public abstract string Name { get ; }
public void DoWork ( ) { OnDoWork(); }
public void Suspend ( ) { m_evtPause.Clear(); }
public void Resume ( ) { m_evtPause.Set(); }
protected abstract void OnDoWork ( );
}
public class FixDogWorkItem : WorkItem
{
public override string Name { get { return "Fix dog"; } }
protected override void OnDoWork ( ) { ... }
}
This is sort of standard for all but the simplest thread routines. Create a class to hold the data and then call a class method. Then you don't have to pass a lot of parameters around nor rely on global objects.
Now to your original question of pausing/resuming threads. I would go the event route such that each WorkItem has its own event. The OnDoWork() method must periodically check this event and when it is cleared (it should initially be set) block using WaitOne().
protected override void OnDoWork ( )
{
//Looping operations
while (m_evtPause.WaitOne(Timeout.Infinite))
}
Now it simply becomes a matter of how to expose this option to the user. If you are using a thread pool manager then it already has the list of work items being run so it could provide you the list of items (through their names). It simply calls Pause/Resume as needed on the work item. Note that I used a single event here but you should really have a global terminate event that all threads listen for as well. This event is set by the thread manager when it is terminating. Otherwise a user can't shut down your app until all work items are completed.
Note that you could avoid the overhead of an event by using a boolean flag but then you couldn't efficiently pause the thread. You'd have to use a spinlock or something. Due to the thread/event combo you really need to prevent too many work items from running at once through a queue system as discussed earlier.
Finally, note that some apps use a far more advanced system where work items are sufficiently isolated enough that each one can run on an arbitrary thread and the thread can be changed each time the work item loops through. This makes pause/resume easy because either the thread manager keeps multiple queues to control whether a work item gets executed this "cycle" or the work item itself stores its own state (Runnable, Paused, etc.) This is technically how threads themselves work but it is far more work than you need right now.
Good luck,
Michael Taylor - 12/16/05
SteveJF
John Tacke
Cablehead, updating a UI component from a secondary thread using BeginInvoke is pretty easy and has been documented in this forum and in various articles (I demonstrated it in an article I wrote for DDJ a year ago). Although it is caused by threading it itself is not something that is necessarily an issue when threading is used.
What you have requested is slightly different than what Doug has been asking for. In your case you want a relatively simple example of threading that works properly with a UI and can pause/resume operations. This is doable and has been done many times. Unfortunately simple solutions do not work well in scalable environments. Furthermore such a coding example would be too long to post here. The code alone with be over 100 or so lines of code and would have to ignore some of the more critical issues like comments and exception handling.
For the example you want I would probably just whip something together. Nothing fancy. However for what Doug has requested I would lean toward a threading subsystem that would involve a couple of classes and would be extensible to support the addition of new work items. That would definitely not fit in a forum post. Perhaps I should write an article about such a system and publish it in DDJ or something It wouldn't be too long but an article gives you more room to move. I shy away from online articles because anybody can write them and therefore you shouldn't believe everything you read.
I'm not really sure what you meant by an endless loop. An endless loop is normally used in thread code to prevent the thread from exiting. Using WaitOne or any of the related functions truly does put a thread to sleep because the underlying OS will remove the thread from the ready queue until the condition is met. This is effectively how Thread.Sleep works as well but in that case the condition is time based.
Michael Taylor - 12/17/05
icedfire007
Taylor -- I *really* hope you're not on holiday yet!
I've been working with all the thread information you've provided above. Pretty interesting stuff for a newbie.
I've come to a couple of "conclusions" that I was hoping you would comment on to see if my understanding is correct. I also have a couple of additional questions.
Item 1: If you declare an array of type Thread and then instantiate several threads of the same class (each is a running thread of the same class with a similar purpose, such as an endless loop that every 30 seconds runs a slightly different query against SQL Server), the resulting threads share the "same" class variables.
For example:
Set up the MyThreads array of type Thread:
int i; Thread[] MyThreads = new Thread[4]; for (i=0; i < MyThreads.Length; i++){
MyThreads
=
new Thread(new ThreadStart(MyTask.ThreadDoWork));MyThreads
.Name =
"MyThread" + i.ToString();}
Start up four threads of the same object class:
for (i = 0; i < MyThreads.Length; i++){
MyThreads
.Start();
Thread.Sleep(1);}
The ThreadDoWork method in the class that all the threads are using has a WaitHandle:
WaitHandle[] myHandles =
new WaitHandle[] {myThreadTerminate, myThreadPause};OK, if I send a ManualResetEvent with a WaitAny to "pause the threads" into myHandles, all four of my threads see this event and pause. If I send an AutoResetEvent into myHandles the first thread that sees the event acts on it and then it resets before the other threads see it. The remaining threads won't see it and are not impacted. The important point is that all the threads appear to be acting on the same myHandles area in memory (I think reference variable is the proper term.)
Additionally, if I have a value variable declared in the ThreadDoWork method of the common class (ex. int currentHotDogTemperature) then each of the threads appears to read and write from this one same value variable in memory.
Therefore, proper synchronization of all this requires using the various Mutex / Monitor / Locking / WaitHandle features in C# to ensure that if one thread is working with a variable (such as currentHotDogTemperature) that another thread cannot change the same variable value until the first thread has released the lock. If one thread has a lock on currentHotDogTemperature, other threads requiring that variable will block until it is their turn to access currentHotDogTemperature.
Therefore, you don't want to have multiple copies of the same class running as threads (almost a homegrown ThreadPool) if you know that all of the threads will be concurrently running all of the time (as in my endless loop) and some of the critical areas that will have to be locked in the class will require a long time to execute (as in my items related to the various SQL queries.)
For example, an area of code in the class that accesses a SQL Server and runs a query for 30 seconds would require a lot of synchronization locking of variables, connections and only my dog really knows what else. All the other threads of the same class that need to run a similar query using connections, etc. will wind up waiting for the various SQL query related locks to be released, so you're essentially "single threading" the operation. Sounds pretty un-fun.
Therefore, more threads of the same class as above doesn't necessarily equal more net work completed if all the threads are continuously busy and competing for the same areas in memory that have to be synchronized.
A scenario using the same class as per above would be more effective with a true thread pool where threads are not always continuously busy, and the actions the threads carry out are relatively quick.
Sound correct, or am I totally confused
Item 2: OK, so if I want to build a server that does behave as described above, I'm guessing I have to actually launch each thread against an individual class. For example, if I want three continuously operating threads with private memory areas that won't require a lot of complex synchronization then I need:
thread #1 with CalcHotDogTempClass1
thread #2 with CalcHotDogTempClass2
thread #3 with CalcHotDogTempClass3
... etc.
If this is true then I have to know in advance how many threads I'm going to need, and have to have previously set up/hardcoded the individually named classes in my application....ouch....or do I
I'd really like to be able to dynamically determine the number of threads to start at runtime, I guess with distinct class names (or at least non-competing areas of memory) as per above.
I know that I can inherit a lot of the threading mechanics and class behaviors as you've shown earlier ... which is really great ... but I'm really wondering if there is any way around this problem of having to know in advance Or, again am I totally confused
Item 3: Assuming I'm working with just one thread and class ... I've found examples of setting up initial state information for the class when the thread is started. This looks pretty straightforward. I could use this to give the thread initial SQL Server login information, etc.
Once the thread has started, from your earlier examples I've figured out how to send an AutoResetEvent from Main into the thread to instruct it to perform some piece of application code. This is beyond the basic thread Pause, Continue, Terminate. etc.
For example, I've figured out how to send an event in that could instruct the thread running the CalculateHotDogTempClass on-the-fly to calculate the temperature in Celsius or in Fahrenheit. Pretty cool.
What I'm wondering about is the preferred method of providing variable data values from Main to a running thread. The same applies to retrieving data values that a thread may have set back to Main. Here's the scenario:
I start my CalcHotDogTempClass and thread from Main. The class calculates hot dog temperatures in Fahrenheit.
From Main, I send an event into the thread to tell it to switch calculations to Celsius. Additionally, I want to tell the thread to increase the resulting temperature by 10 degrees. So, I'm sending an event, and I have to have a way to get the variable 10 degree value into the running thread.
Also, from Main, I want to be able to send a new "Report Status" event into the thread. The thread determines several status values such as the number of times it has been run, the average of all the hot dog temperatures it has calculated, and possibly other values. I then need to see the resulting values back in Main.
Is it as simple as just setting up the variables in Main and having the thread read and write to the variables I can handle the event requests, but I'm not sure how to manage the storage of the data. What's the best approach Obvious newbie here....
Whew!
Thanks again....
Doug
Eddie NG
You could but using Thread.Abort is like hitting the power switch to shut down Windows, you really only want to do that when nothing else will work. I eluded to the solution in my earlier approach when I talked about terminating the threads when the app closes.
If you want to be able to terminate individual work items then you'll need another event (the terminate event). Instead of using WaitOne on the pause/resume event you'll switch to using WaitHandle.WaitAny. You'll specify both the terminate event and the pause/resume event in the parameters. Then whenever either event is raised your thread will resume. Normally you can use the return value from the function to determine which event satisified the request but in your case you expect the pause/resume event to normally be set and therefore you might or might not ever see the terminate event. Therefore I would recommend that after the method returns you immediately call terminateEvent.WaitOne(0) to see if the event is set. If it is then your thread should terminate (return from the function and the thread will terminate). Something like this:
//In your work item
ManualResetEvent m_evtTerminate = new ManualResetEvent(false);
//In your worker thread
WaitHandle[] handles = new WaitHandle[] { m_evtTerminate, m_evtPause };
while (true)
{
WaitHandle.WaitAny(handles);
if (m_evtTerminate.WaitOne(0))
{
//Time to terminate
};
//Do normal work
}
In your thread manager class set the event for each work item to terminate all threads when the app closes. You can optionally also call Thread.Join() to wait for a fixed amount of time. If the thread doesn't terminate then call Thread.Abort() to force it to go away. I might not have mentioned it earlier but you'll also want to mark your threads as background threads so they won't prevent the process from terminating.
Michael Taylor - 12/16/05
globim
Michael ... Thank you so much for your patience.
I think I follow most of the above. And I'm *REALLY* looking forward to your article!
Here's one thing that is still not clear to me....and again thank you for putting up with the newbie....
In regards to Item 2 first, you only need to create a single class type to wrap all your work. Then instantiate a separate class for each thread. Therefore you can dynamically create as many threads as you need each using its own instance of a single class. A class is simply a type definition so you'll want to reuse it whereever you can.
OK, I get the idea of wrapping everything that is common in an abstract Base ThreadClass. Then I create a CalcTempThreadClass that inherits all the functionality of BaseThreadClass. When I run the following I create an object instance named checkTemp01:
CalcTempThreadClass checkTemp01 = new CalcTempThreadClass();
checkTemp01 is an object of type CalcTempThreadClass, so it has its own memory structures, etc. which is what I want. It inherits all the capabilities from the base class. I get to leverage all the reuse of code I've already written. Based on all your earlier information I've set this up and it works like a champ!
Here's the concept I'm stuck on (and maybe this is just not the right practice so tell me if this is pilot error): as I'm developing my application, I'm not sure how many instances of CalcTempThreadClass I may need to run at one time. This application may run on hosts with many CPUs. I'd like to allow from 1 - n instances of CalcTempThreadClass to be instantiated at runtime. BTW, understand that CalTempThreadClass is just an example, I get what you're saying above about not actually using a thread for this. I suppose Foo would have been a better choice...
What I'm missing is how to do this without having to hardcode something like the following in my code:
CalcTempThreadClass checkTemp01 = new CalcTempThreadClass();
CalcTempThreadClass checkTemp02 = new CalcTempThreadClass();
CalcTempThreadClass checkTemp03 = new CalcTempThreadClass();
CalcTempThreadClass checkTemp04 = new CalcTempThreadClass();
...etc. up to a maximum number of instances
I figure there has to be an array / collection / loop or some other technique that will instantiate n number of CalcTempThreadClass objects, each with a separate name (checkTemp01, checkTemp02, etc.) or index reference I can use to call methods for a specific instance of CalcTempThreadClass. I haven't been able to track down any documentation examples that show a technique for this.
I think this is the last piece of the pie that I'm missing. Any help would be appreciated.
Thanks, and again please allow for pilot error here...
DB
GoCoda
Is MyTask a class (in which case ThreadDoWork must be a static method), or is it an instantiated object e.g.,
for (i=0; i < MyThreads.Length; i++)
{
MyTaskClass MyTask = new MyTaskClass();
MyThreads
= new Thread(new ThreadStart(MyTask.ThreadDoWork));
}
If it is a class then all the threads will share the fields in the class (which will need to be declared static) and you need to synchronise access. If it is an object, then each thread will have its own MyTask object, and its own copy of the fields in the object, so no synchronisation is required. If you still want to share a particular field (e.g., a WaitHandle) between all the objects of this class, then declare the field as static.
Shannon Braun
Good information...let me think this over. This may help a lot!
Michael....you there buddy
DB
Akram Hussein
Michael -
Thanks again so much for your help with this. I was able to experiment quite a bit and I believe I've pieced together what I need based on your suggestions.
I may come back later on a different thread with follow-up questions, but for the moment I'm in good shape. The most amazing part is that I think I actually understand why it works ....
...Teach a man to fish ....
Super job!
DB
anat52349
Wow! A lot more information for a new guy like me to absorb! Let me look through this and see if I can understand/implement it.
Michael, did you ever think of putting all this together in an article It seems like there are a lot of facts you're referencing available in the individual/various docs and on-line references, but this is the first time I've seen someone (kindly) work toward putting together the "big picture" of all the components and how to use them in an app. Especially for those of us who are facing properly implementing a multi-threaded app the first time.
A compliment as well as a suggestion!
More to come, I'm sure....thanks again for your patience and assistance.
Doug