|
ms
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Multi threaded design patternsI'd like to bounce some things off developers and MSDN folks that are here. I have a Windows service MyService that is the main application. It will build a MyWorkObject in it's constructor and the OnStart and OnStop methods set a property that will start/stop a worker thread or threads. The worker thread(s) will process a queue and the dequeued item will be processed by some asynchronous process. Just a few questions for starters: 1. Is the general framework of this OK? That is, the service constructor creates an object and OnStart/OnStop methods start/stop worker threads? 2. If garbage collection is no panacea, what questions do I need to ask to determine the disposal process of MyObject and objects that it creates? 3. What threading design should I use to handle the myWorkQueueX.Process() so that it will block until there is an item in the queue to process and the current item is finished being processed? Is this an application for some sort of ThreadPool construct? The code below is an abstraction of a rough 1st attempt and included to facilitate discussion. All comments, ideas and criticism are welcome. Thanks, Bill //Project MyNamespace1.csproj //Source: MyNamespace1.cs //Creates: MyNamespace1.exe using MyNamespace2 namespace MyNamespace1 { public partial class MyService : ServiceBase { private MyWorkObject myWorkObject; public MyService() { InitializeComponent(); myWorkObject = new MyWorkObject(); } protected override void OnStart(string[] args) { myWorkObject.MyWorkerThreadRun = true; } protected override void OnStop() { myWorkObject.MyWorkerThreadRun = false; } } } //Project MyNamespace2.csproj //Source: MyNamespace2.cs //Creates: MyNamespace2.dll namespace MyNamespace2 { public class MyWorkObject { private static MyWorkQueue1 myWorkQueue1; private static MyWorkQueue2 myWorkQueue2; private Thread myWorkerThread; private bool myWorkerThreadRunning; private bool myWorkerThreadRun; public bool MyWorkerThreadRun { set { myWorkerThreadRun = value; if (myWorkerThreadRun && !myWorkerThreadRunning) myWorkerThread.Start(); } } public MyObject() { myWorkerThread = new Thread(this.myWorker); } private void myWorker() { myWorkQueue1 = new MyWorkQueue1(); myWorkQueue2 = new MyWorkQueue2(); try { while (myWorkerThreadRun) { if (!myWorkerThreadRunning) { myWorkerThreadRunning = true; } myWorkQueue1.Process(); myWorkQueue2.Process(); Thread.Sleep(20); } } catch (Exception ex) { //do some logging } finally { myWorkerThreadRunning = false; }//end try }//end myWorker }//end MyWorkObject }//end MyNamespace2 On Fri, 19 Dec 2008 14:11:45 -0800, Bill McCormick
<wpmccormick@newsgroup.nospam> wrote: Show quoteHide quote > Hello, I don't have enough knowledge about writing services to know for sure. > > I'd like to bounce some things off developers and MSDN folks that are > here. > > I have a Windows service MyService that is the main application. It will > build a MyWorkObject in it's constructor and the OnStart and OnStop > methods set a property that will start/stop a worker thread or threads. > The worker thread(s) will process a queue and the dequeued item will be > processed by some asynchronous process. > > Just a few questions for starters: > > 1. Is the general framework of this OK? That is, the service constructor > creates an object and OnStart/OnStop methods start/stop worker threads? But it seems fine to me, assuming you manage the threads correctly. > 2. If garbage collection is no panacea, what questions do I need to ask I don't understand this question. Of course, you should not rely on GC to > to determine the disposal process of MyObject and objects that it > creates? deal with thread management, but then I didn't support that you thought that you did. GC is fine for dealing with memory management, and for other things you need to include logic to shut things down when they are no longer needed. > 3. What threading design should I use to handle the The ThreadPool could be used, yes. In that case, you'd probably keep > myWorkQueueX.Process() so that it will block until there is an item in > the queue to process and the current item is finished being processed? > Is this an application for some sort of ThreadPool construct? track of whether there's already a worker thread doing the processing, queueing a new work item to the ThreadPool if there's not. The worker thread would in turn keep working until it's exhausted the queue, and then would exit. I think it's more traditional though to just create a dedicated thread for the purpose of processing the queue. In that case, you can use the Monitor class to do things like Wait() and Pulse() so that consumers and producers can communicate changes to the queue to each other. Pete Peter Duniho wrote:
Show quoteHide quote > On Fri, 19 Dec 2008 14:11:45 -0800, Bill McCormick Right. This has less to do with thread management and more to do with GC > <wpmccormick@newsgroup.nospam> wrote: > [SNIP] > >> 2. If garbage collection is no panacea, what questions do I need to >> ask to determine the disposal process of MyObject and objects that it >> creates? > > I don't understand this question. Of course, you should not rely on GC > to deal with thread management, but then I didn't support that you > thought that you did. GC is fine for dealing with memory management, > and for other things you need to include logic to shut things down when > they are no longer needed. > under a Windows service. I should have chosen a better subject line. Still, I suppose memory needs to managed correctly if the application is to manage threads correctly. Anyway ... I'm not sure if there should be any sort of object disposal when the service is stopped. Or maybe I should be creating the process objects OnStart and doing some cleanup/disposal OnStop? Perhaps the right question to ask is this: when does the service constructor run? Just before OnStart? Or does it run when the Windows service manager loads the service? If it runs on service load, then it would seem not to make sense to have a stopped service burden the OS with unused recourses (memory)? And if so, then should object creation generally happen OnStart? Which would require disposal OnStop? If, instead, the constructor runs just before OnStart, then should some cleanup OnStop be done for objects that won't get GC'd? Maybe a more general question is: are there rules or extra considerations for GC in a Windows service? Show quoteHide quote >> 3. What threading design should I use to handle the For the latter, do you have a design pattern or some other sort of >> myWorkQueueX.Process() so that it will block until there is an item in >> the queue to process and the current item is finished being processed? >> Is this an application for some sort of ThreadPool construct? > > The ThreadPool could be used, yes. In that case, you'd probably keep > track of whether there's already a worker thread doing the processing, > queueing a new work item to the ThreadPool if there's not. The worker > thread would in turn keep working until it's exhausted the queue, and > then would exit. > > I think it's more traditional though to just create a dedicated thread > for the purpose of processing the queue. In that case, you can use the > Monitor class to do things like Wait() and Pulse() so that consumers and > producers can communicate changes to the queue to each other. example I could reference? Thanks, Bill I tend not to implement the service code within the service itself. I
create dedicated classes for handling different parts of the solution A: Monitor directory for new files. B: A factory to create a concrete descendant of FileProcessor depending on the file name / location. C: A queue to hold instances of Process in so that they can be processed in order of receipt. D: A dequeuer which has X number of worker threads which dequeues the next job from the queue. I went for this approach because I had 3 queues, high, normal, low priority. E: The various FileProcessor descendants. The classes above act as my "business domain" (what to do), leaving the sole responsibility of the service to be to link them together and start/stop the dequeuer (an application layer that coordinates the business domain objects). The monitor's NewFile event is wired up to an event that pushes the file name into the process factory. The process factory returns the FileProcessor (which has a Priority property) and I add that FileProcessor to the relevant queue. The dequeuer is constantly running so it just executes each process in turn. When I stop the service I tell the monitor to stop looking for new files, I tell the dequeuer to empty its queues. When I start the service I tell the monitor to start looking for files (on startup it triggers the event for every file that already exists), and the dequeuer to reactivate. The service keeps requesting more time to stop while it waits for the current processors to finish, this prevents you from restarting the service before it has finished stopping. It also makes it very easy to unit test :-)
Other interesting topics
Inheritance problem
Inheritance - Accessing two levels above mine - Now with virtual+override Finding a specific element using LINQ Mapping Combobox doesn't work if the form has TopMost = true how to convert a byte array with string,int and double embeded? Inherit Overrides Do SingleCall server activation objects retain state across calls? Linq To Sql: Contains any. Class and Methods access |
|||||||||||||||||||||||