Anyway to know when a pooled thread (or ThreadStatic member) is destroyed?
.net, .net-3.5, multithreading, threadpool
Solution
If the worst comes to the worst, and no better solution is forthcoming, you could make a threadpool of your own with a fixed number of threads, (=num of cores?). By creating a 3PC instance in each thread and calling Initialize(), you should, hopefully, be OK.
Something like:
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
namespace WindowsPoolApp
{
public abstract class Task {
public EventHandler FonComplete;
public ThreadPool myPool;
protected int param;
public Exception error;
public Task(int inParam, EventHandler OnDone) { param = inParam; FonComplete = OnDone; }
public abstract void run();
};
public class PoolThread{
private
3PC my3PC;
BlockingCollection<Task> FinQueue;
public
PoolThread(BlockingCollection<Task> inQueue)
{
FinQueue=inQueue;
}
Task inMess;
public void run(){
my3PC = new 3PC();
my3PC.Initialize();
while(true){
inMess=FinQueue.Take();
if(inMess==null){
my3PC.Teardown();
return;
}
try
{
inMess.run();
inMess.error = null;
}
catch (Exception e)
{
inMess.error = e;
}
inMess.FonComplete(inMess, null);
}
}
};
public class ThreadPool {
volatile int FthreadCount;
BlockingCollection<Task> queue;
void startThread(){
PoolThread thisPoolThread=new PoolThread(queue);
Thread thisThread=new Thread(new ThreadStart(thisPoolThread.run));
thisThread.Priority = ThreadPriority.BelowNormal;
thisThread.IsBackground = true;
thisThread.Start();
}
void SetThreadCount(int newCount){
while(FthreadCount<newCount){startThread();};
while(FthreadCount>newCount){
queue.Add(default(Task));
FthreadCount--;
};
}
public ThreadPool(int initThreads){
queue=new BlockingCollection<Task>();
for(FthreadCount=0;FthreadCount<initThreads;FthreadCount++) startThread();
}
public int threadCount{
get{return FthreadCount;}
set
{
while (FthreadCount < value) {
startThread();
FthreadCount++;
};
while (FthreadCount > value)
{
queue.Add(default(Task));
FthreadCount--;
}
}
}
public void submit(Task task){
task.myPool=this;
queue.Add(task);
}
};
}
To start it up, call 'new ThreadPool(numThreads);', to shut down, set the 'threadCount' property to 0.
Problem
I need to add a third party component to one of our products (which is a windows service that can run 24/7). The 3PC is a .net library that sits on some hard core C++ loveliness for manipulating images. The 3PC requires that Initialize and Teardown routines are called for every thread it runs on. This is fine where we use it in our older software, but this product was written with the .Net thread pool, and pooled workers will exercise the 3PC. I can't figure out how to safely call the Initialize and Teardown routines. The closest I got was when initializing a ThreadStatic member, to call the 3PC `Initialize` method, however I can't manage to call the `Teardown` on the same thread the `Initialize` was called on. If I wrap the `Initialize` and `Teardown` in an object, with the `Teardown` called in the objects Finalize method, then the `Teardown` will be called by the GC's own Finalize thread, not the thread the object is static to (not to mention the fact that there's no guarantee the Finalizer will ever run). Obviously I'm worried about leaked resources as the the thread pool manages threads under the covers, I have no idea if or when threads will be destroyed or created, so I've no idea how much the Service could leak over a period of time. Anyone any ideas? Anything I've missed? Anything else to try? Thanks Update Q: What does Teardown do? I'm assuming it "Releases some memory", but I honestly have no idea. I tried splunking through the assembly with Reflector but it quickly drops from IL into native machine code. I'm going on the (3rd) party line that this must be done. It definitely is a subsystem tear down thing. Also, several years ago we discovered a bug around this component in another Product. The Initializer wasn't being called for every thread which resulted in some very rarely seen Undefined behaviour.