Reputation: 9736
I have a fairly complex multi-threaded Windows service working, but I can't figure out how to clean up correctly. Below is some [pseudo] code to show what I have. The actual code is much more complex, probably too much to copy/paste here.
Basically, I have a class Request that creates a thread to do the work. When a new request comes in the Listener, it sends it to the Processor, which creates the new Request and maintains the list of requests. If the service is stopped, I cleanup all the requests in the list. But when the Request work is done, how do I clean up that one instance of the class?
Thanks for any help!
Nelson
class Service
{
Listener listener;
Processor processor;
OnStart()
{
processor = new Processor();
listener = new Listener(processor);
}
OnStop()
{
listener.Dispose();
processor.Dispose();
}
}
class Listener
{
Thread thread;
bool terminate = false;
Listener(Processor processor)
{
thread = new Thread(DoWork);
thread.Start(processor);
}
DoWork(Processor processor)
{
WaitForConnection(NewConnection);
}
NewConnection(String data)
{
processor.NewRequest(data);
if (terminate)
return;
WaitForConnection(NewConnection);
}
Dispose()
{
terminate = true;
thread.Join();
}
}
class Processor
{
//I need to maintain this list so that when the service stops I can cleanly close down
List<Request> requests = new List<Request>();
NewRequest(string data)
{
request.Add(new Request(data));
}
Dispose()
{
//Cleanup each request
foreach (Request request in requests)
{
request.Dispose();
}
}
}
class Request
{
Thread thread;
bool terminate;
Request(string data)
{
while (true)
{
//Do some work
Thread.Sleep(1000);
if (doneWorking)
break;
if (terminate)
return;
}
//We're done. If I return this thread stops. But how do I properly remove this Request instance from the Processor.requests list?
}
Dispose()
{
terminate = true;
thread.Join();
}
}
Upvotes: 4
Views: 14341
Reputation: 64218
This is a rough sketch:
delegate void CompletedRequest(Request req);
class Processor : ITrackCompletion
{
//I need to maintain this list so that when the service stops I can cleanly close down
List<Request> requests = new List<Request>();
public void NewRequest(string data)
{
lock(requests)
request.Add(new Request(data), Complete);
}
public void Complete(Request req)
{
lock (requests)
requests.Remove(req);
}
public void Dispose()
{
//Cleanup each request
foreach (Request request in requests.ToArray())
{
request.Dispose();
}
}
}
class Request
{
Thread thread;
bool terminate;
public Request(string data, CompletedRequest complete)
{
try
{
while (true)
{
//Do some work
Thread.Sleep(1000);
if (doneWorking)
break;
if (terminate)
return;
}
}
finally
{
//We're done. If I return this thread stops. But how do I properly remove this Request instance from the Processor.requests list?
complete(this);
}
}
void Dispose()
{
terminate = true;
thread.Join();
}
}
Upvotes: 4
Reputation: 1499760
One possibility is to pass a callback to the request in the form of a delegate: "when you've finished processing, call me back to tell me". Then just execute the callback at the end of the request processing and let it handle the cleanup.
One thing to watch out for though: if you try to go through your list disposing things and then try to remove an item from the list in another thread, you'll get problems. You should probably keep a flag (accessed in a thread-safe way) and once you've started disposing of everything in the list, ignore any callbacks you get.
Upvotes: 4