S
Stephen Engle
I have an app that I am working on that is dependent on an unmanaged code
library. There is a middle library of managed C++ that encapsulates the
unmanaged libary functions calls into a class.
What is happening is that I create an instance of this class in a separate
thread and use it to call certain functions. But when I call GC.Collect
(which is necessary for some timely cleanup) from the main thread, the
garbage collector deletes the class from my first worker thread before the
functions that the thread is calling have finished.
I'm hoping to find a way to prevent this.
My code resembles the following though I have a couple different worker
threads and the timer function calls each of them according to different
timing settings. Specifically, it's the DLMngr object in the worker thread
function GetDLAList that gets collected before the GetObjectList function
from the underlying library finishes.
I cannot understand how that can happen since the DLMngr object is calling
the function GetObjectList. This does happen to more than one of my worker
threads but since most of them only call one function in the underlying
library, they do not have adverse results. But one calls several functions
and each of them checks for data initialized when the DLMngr object is
created. If that data is not there the function fails.
Can anyone tell me why these objects are being collected before the
functions are finished executing?
public unsafe class WorkerThreadA
{
public static int * Result;
public static System.IntPtr ResultPtr;
private static void GetDLAList()
{
int result=-1;
DLMngr dlm=new DLMngr();
if(Result!=null)
{
result=dlm.GetObjectList();
*Result=result;
}
dlm=null;
}
public static void ThreadGetDLAList(System.IntPtr result, ref Thread
threada)
{
ThreadStart thread;
Result=(int *)result.ToPointer();
ResultPtr=result;
thread=new ThreadStart(GetDLAList);
threada=new Thread(thread);
threada.Start();
}
}
public class Form1 : System.Windows.Forms.Form
{
...
private Thread ThreadObject=null;
private ThreadStart TSObject=null;
private GCHandle GCHListObjectNew=new GCHandle();
private ArrayList ArrayObjectCurrent=new ArrayList();
private ArrayList ArrayObjectNew=new ArrayList();
private int ListObjectCurrent=-1;
private int ListObjectNew=-1;
...
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
GCHListObjectNew=GCHandle.Alloc(ListObjectNew, GCHandleType.Pinned);
}
...
private unsafe void TimerUpdate_Tick(object sender, System.EventArgs e)
{
String objectid=new String('c', 10);
int errorval;
FileTime ft=new FileTime();
System.IntPtr sipr;
SystemTime st=new SystemTime();
TimeSpan tsobject=new TimeSpan(0, 0, 6, 0, 0);
TimeSpan tsdisp;
System.Int32 checkr;
// check for new object list
//
checkr=(System.Int32)GCHListObjectNew.Target;
if(ListObjectNew!=checkr) ListObjectNew=checkr;
if(ListObjectCurrent!=ListObjectNew)
{
// remove thread data since thread is finished
//
if(ThreadObject!=null) ThreadObject=null;
if(TSObject!=null) TSObject=null;
GC.Collect();
// update data returned by thread
//
ListObjectCurrent=ListObjectNew;
ArrayObjectNew.Clear();
gblitem=DLM.UserFirstItem(ListObjectCurrent, ref objectid, &errorval);
while(gblitem==true && errorval==0)
{
ArrayRecipientNew.Add(new DataObject(objectid));
gblitem=DLM.UserNextItem(ListObjectCurrent ref objectid, &errorval);
}
UpdatingObjects=false;
ArrayObjectNew.Sort();
}
LibWrap.GetSystemTime(st);
LibWrap.SystemTimeToFileTime(st, ft);
lt=ft.highdatetime;
lt=lt<<32;
lt=lt+ft.lowdatetime;
DateTime dt=new DateTime(lt);
// check for time to update object list
//
tsdisp=dt-LastUpdateObject;
if(dt-LastUpdateObject>tsobject && UpdatingObjectss==false)
{
UpdatingObjectss=true;
sipr=GCHListObjectNew.AddrOfPinnedObject();
WorkerThreadA.ThreadGetObjectList(sipr, ref ThreadObject, ref TSObject);
LastUpdateObject=dt;
}
}
}
library. There is a middle library of managed C++ that encapsulates the
unmanaged libary functions calls into a class.
What is happening is that I create an instance of this class in a separate
thread and use it to call certain functions. But when I call GC.Collect
(which is necessary for some timely cleanup) from the main thread, the
garbage collector deletes the class from my first worker thread before the
functions that the thread is calling have finished.
I'm hoping to find a way to prevent this.
My code resembles the following though I have a couple different worker
threads and the timer function calls each of them according to different
timing settings. Specifically, it's the DLMngr object in the worker thread
function GetDLAList that gets collected before the GetObjectList function
from the underlying library finishes.
I cannot understand how that can happen since the DLMngr object is calling
the function GetObjectList. This does happen to more than one of my worker
threads but since most of them only call one function in the underlying
library, they do not have adverse results. But one calls several functions
and each of them checks for data initialized when the DLMngr object is
created. If that data is not there the function fails.
Can anyone tell me why these objects are being collected before the
functions are finished executing?
public unsafe class WorkerThreadA
{
public static int * Result;
public static System.IntPtr ResultPtr;
private static void GetDLAList()
{
int result=-1;
DLMngr dlm=new DLMngr();
if(Result!=null)
{
result=dlm.GetObjectList();
*Result=result;
}
dlm=null;
}
public static void ThreadGetDLAList(System.IntPtr result, ref Thread
threada)
{
ThreadStart thread;
Result=(int *)result.ToPointer();
ResultPtr=result;
thread=new ThreadStart(GetDLAList);
threada=new Thread(thread);
threada.Start();
}
}
public class Form1 : System.Windows.Forms.Form
{
...
private Thread ThreadObject=null;
private ThreadStart TSObject=null;
private GCHandle GCHListObjectNew=new GCHandle();
private ArrayList ArrayObjectCurrent=new ArrayList();
private ArrayList ArrayObjectNew=new ArrayList();
private int ListObjectCurrent=-1;
private int ListObjectNew=-1;
...
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
GCHListObjectNew=GCHandle.Alloc(ListObjectNew, GCHandleType.Pinned);
}
...
private unsafe void TimerUpdate_Tick(object sender, System.EventArgs e)
{
String objectid=new String('c', 10);
int errorval;
FileTime ft=new FileTime();
System.IntPtr sipr;
SystemTime st=new SystemTime();
TimeSpan tsobject=new TimeSpan(0, 0, 6, 0, 0);
TimeSpan tsdisp;
System.Int32 checkr;
// check for new object list
//
checkr=(System.Int32)GCHListObjectNew.Target;
if(ListObjectNew!=checkr) ListObjectNew=checkr;
if(ListObjectCurrent!=ListObjectNew)
{
// remove thread data since thread is finished
//
if(ThreadObject!=null) ThreadObject=null;
if(TSObject!=null) TSObject=null;
GC.Collect();
// update data returned by thread
//
ListObjectCurrent=ListObjectNew;
ArrayObjectNew.Clear();
gblitem=DLM.UserFirstItem(ListObjectCurrent, ref objectid, &errorval);
while(gblitem==true && errorval==0)
{
ArrayRecipientNew.Add(new DataObject(objectid));
gblitem=DLM.UserNextItem(ListObjectCurrent ref objectid, &errorval);
}
UpdatingObjects=false;
ArrayObjectNew.Sort();
}
LibWrap.GetSystemTime(st);
LibWrap.SystemTimeToFileTime(st, ft);
lt=ft.highdatetime;
lt=lt<<32;
lt=lt+ft.lowdatetime;
DateTime dt=new DateTime(lt);
// check for time to update object list
//
tsdisp=dt-LastUpdateObject;
if(dt-LastUpdateObject>tsobject && UpdatingObjectss==false)
{
UpdatingObjectss=true;
sipr=GCHListObjectNew.AddrOfPinnedObject();
WorkerThreadA.ThreadGetObjectList(sipr, ref ThreadObject, ref TSObject);
LastUpdateObject=dt;
}
}
}