Bob wrote:
Hi,
I have an app that has a 3rd party phone answering control (4 of )
(interfacing with dialogic 4 line card) attached to the main form.
each control raises an event when its Dialogic line detects ring tone.
I use the ring detect event handler to create a new thread which is given a
reference to the control that is being rung. The called method then
interacts with the control until the call finishes.
My problem is that I believe I am getting thread blocking between the
threads that are dealing with the calls.
There doesn't appear to be any consistent pattern to the blocking and I was
wondering what techniques I can use to further investigate this. I have run
the app under a commercial profiler but there is nothing definitive showing.
Each of the phone call threads seem to get roughly the same time.
The blocking occurs when the phone handling objects are getting input from
phone users. (DTMF tones) but varies at which point it occurs.
Initiating Code from one of the four ring detect event handlers follows:
telecall te = new telecall();//Class that contains state engine to handle
call
te.TraceMessage += new telecall.TraceMessageEventHandler(te_TraceMessage) ;//
info back from state engine
te.LineStateChange += new
telecall.LineStateChangeEventHandler(this.SetLineS tatus); // Phone line
status back from state engine
te.MyForm = this;//Ref to stop orphans
te.Vbocx = ((AxVbocxLibrary.AxVBocx)(sender));//Assigning ref to the line
handling object.
ThreadStart ts = new ThreadStart(te.HandleCall);// State engine
Thread t = new Thread(ts);
t.Name = "PH1";
t.SetApartmentState(ApartmentState.STA);//desperation
t.Start();
>From the COM library reference, it appears that you are using an older
version of CallSuite... Those are STA Com Objects, and as such each
one must exist on it's own thread or you need to use the async methods
methods provided by the control or they will block each other. One way
I have over come this, is to write a wrapper class for the VoiceBocx
object that spawns a thread in the constructor. that intializes the
object and then calls Application.Run. I use a ManualReset Event to
signal that intialization has completed. It is complex I guess, but it
works well. I use a newer version - 9.1, and I don't use the ActiveX
control - only the object, but this code was written with the older
version originally. The code here is not all of the code, nor is it
actually working code - it is just a bit to illustrate the point:
public sealed class Trunk : System.IDisposable
{
private ADXVoiceClass trunk;
private ManualResetEvent intialized;
private Exception startup;
public Trunk(int channel)
{
this.startup = null;
/ set this so that we can signal initilization...
this.intialized = new ManualResetEvent(false);
// VoiceBocx objects need to exist on their own thread to
// avoid blocking problems. So, we will create an STA Thread,
// create the object and start a message pump for the object.
Thread runner = new Thread (new ThreadStart(this.ObjectThread));
runner.ApartmentState = ApartmentState.STA;
runner.IsBackground = true;
runner.Start ();
// wait for intialization to complete.
this.intialized.WaitOne();
this.intialized.Close();
if (this.startup != null)
{
throw this.startup;
}
}
private void ObjectThread()
{
try
{
// set up the trunk object
InitializeTrunkObject();
// signal the parent!
this.intialized.Set();
// start a message loop for COM events on this thread
Application.Run();
}
catch (Exception ex)
{
this.startup = ex;
this.intialized.Set ();
}
}
..... Lots of other junk
}
The actual working code actually lets you pass in a value to determine
if it creates a thread for the object or not. I am not saying this is
the only (or even the best way), but if you want to use multiple phone
lines in your application, then you will need to use the async model
supported by the VoiceBocx control or arrange to have each line live on
it's own thread.
Anyway,
HTH
--
Tom Shelton