By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,282 Members | 1,511 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,282 IT Pros & Developers. It's quick & easy.

Threading help... threads???

P: n/a
Hello, please find attached a basic outline of what I am attempting to
accomplish... basically I want to create a number of THREADS (which I can do
fine), but I then need a method for them to be able to communicate with each
other, either through a message loop, or some other manner. I ALSO need to
be able to CALL specific functions / subs WITHIN a thread, based on what
another THREAD is doing... here is the attached code... WHEN I click on the
CALLOUT button, it HANGS the thread until it's execution is done:

*** This is where the issue lies - when its called from the main gui, the
thread running it blocks...
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
LineArray(txtCallOutOn.Text).callout()
End Sub
***

CODE BELOW --
Imports System.Threading

Imports System.ComponentModel 'for CancelEventArgs

Imports System.Runtime.InteropServices 'COM support

Public Class Form3

Inherits System.Windows.Forms.Form

'Public WithEvents mVoiceBocx As VoiceBocxLib.VoiceBocx ' VoiceBocx control

Private iNrTrunks As Integer 'maximum number of available trunks

Private LineArray() As TrunkThread

#Region " Windows Form Designer generated code "

Public Sub New()

MyBase.New()

'This call is required by the Windows Form Designer.

InitializeComponent()

'Add any initialization after the InitializeComponent() call

End Sub

'Form overrides dispose to clean up the component list.

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub

'Required by the Windows Form Designer

Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer

'It can be modified using the Windows Form Designer.

'Do not modify it using the code editor.

Friend WithEvents txtIterations As System.Windows.Forms.TextBox

Friend WithEvents ListBox1 As System.Windows.Forms.ListBox

Friend WithEvents ToTrunk As System.Windows.Forms.TextBox

Friend WithEvents Label2 As System.Windows.Forms.Label

Friend WithEvents FromTrunk As System.Windows.Forms.TextBox

Friend WithEvents Label1 As System.Windows.Forms.Label

Friend WithEvents btnStart As System.Windows.Forms.Button

Friend WithEvents btnExit As System.Windows.Forms.Button

Friend WithEvents Button1 As System.Windows.Forms.Button

Friend WithEvents Button2 As System.Windows.Forms.Button

Friend WithEvents txtCallOutOn As System.Windows.Forms.TextBox

Friend WithEvents txtBridge As System.Windows.Forms.TextBox

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

Me.txtIterations = New System.Windows.Forms.TextBox

Me.btnStart = New System.Windows.Forms.Button

Me.ListBox1 = New System.Windows.Forms.ListBox

Me.ToTrunk = New System.Windows.Forms.TextBox

Me.Label2 = New System.Windows.Forms.Label

Me.FromTrunk = New System.Windows.Forms.TextBox

Me.Label1 = New System.Windows.Forms.Label

Me.btnExit = New System.Windows.Forms.Button

Me.Button1 = New System.Windows.Forms.Button

Me.txtCallOutOn = New System.Windows.Forms.TextBox

Me.Button2 = New System.Windows.Forms.Button

Me.txtBridge = New System.Windows.Forms.TextBox

Me.SuspendLayout()

'

'txtIterations

'

Me.txtIterations.Location = New System.Drawing.Point(32, 48)

Me.txtIterations.Name = "txtIterations"

Me.txtIterations.TabIndex = 0

Me.txtIterations.Text = ""

'

'btnStart

'

Me.btnStart.Location = New System.Drawing.Point(160, 48)

Me.btnStart.Name = "btnStart"

Me.btnStart.Size = New System.Drawing.Size(96, 23)

Me.btnStart.TabIndex = 1

Me.btnStart.Text = "Launch Thread"

'

'ListBox1

'

Me.ListBox1.Location = New System.Drawing.Point(16, 88)

Me.ListBox1.Name = "ListBox1"

Me.ListBox1.Size = New System.Drawing.Size(544, 355)

Me.ListBox1.TabIndex = 4

'

'ToTrunk

'

Me.ToTrunk.Location = New System.Drawing.Point(528, 48)

Me.ToTrunk.Name = "ToTrunk"

Me.ToTrunk.Size = New System.Drawing.Size(33, 20)

Me.ToTrunk.TabIndex = 10

Me.ToTrunk.Text = "11"

'

'Label2

'

Me.Label2.Location = New System.Drawing.Point(496, 48)

Me.Label2.Name = "Label2"

Me.Label2.Size = New System.Drawing.Size(27, 21)

Me.Label2.TabIndex = 9

Me.Label2.Text = "To"

'

'FromTrunk

'

Me.FromTrunk.Location = New System.Drawing.Point(448, 48)

Me.FromTrunk.Name = "FromTrunk"

Me.FromTrunk.Size = New System.Drawing.Size(40, 20)

Me.FromTrunk.TabIndex = 8

Me.FromTrunk.Text = "0"

'

'Label1

'

Me.Label1.Location = New System.Drawing.Point(376, 48)

Me.Label1.Name = "Label1"

Me.Label1.Size = New System.Drawing.Size(67, 21)

Me.Label1.TabIndex = 7

Me.Label1.Text = "Use trunks:"

'

'btnExit

'

Me.btnExit.Location = New System.Drawing.Point(272, 48)

Me.btnExit.Name = "btnExit"

Me.btnExit.Size = New System.Drawing.Size(40, 24)

Me.btnExit.TabIndex = 11

Me.btnExit.Text = "Exit"

'

'Button1

'

Me.Button1.Location = New System.Drawing.Point(608, 24)

Me.Button1.Name = "Button1"

Me.Button1.TabIndex = 12

Me.Button1.Text = "Button1"

'

'txtCallOutOn

'

Me.txtCallOutOn.Location = New System.Drawing.Point(608, 56)

Me.txtCallOutOn.Name = "txtCallOutOn"

Me.txtCallOutOn.Size = New System.Drawing.Size(72, 20)

Me.txtCallOutOn.TabIndex = 13

Me.txtCallOutOn.Text = "2"

'

'Button2

'

Me.Button2.Location = New System.Drawing.Point(608, 96)

Me.Button2.Name = "Button2"

Me.Button2.TabIndex = 14

Me.Button2.Text = "Button2"

'

'txtBridge

'

Me.txtBridge.Location = New System.Drawing.Point(608, 128)

Me.txtBridge.Name = "txtBridge"

Me.txtBridge.Size = New System.Drawing.Size(72, 20)

Me.txtBridge.TabIndex = 15

Me.txtBridge.Text = "0"

'

'Form3

'

Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

Me.ClientSize = New System.Drawing.Size(736, 454)

Me.Controls.Add(Me.txtBridge)

Me.Controls.Add(Me.Button2)

Me.Controls.Add(Me.txtCallOutOn)

Me.Controls.Add(Me.Button1)

Me.Controls.Add(Me.btnExit)

Me.Controls.Add(Me.ToTrunk)

Me.Controls.Add(Me.Label2)

Me.Controls.Add(Me.FromTrunk)

Me.Controls.Add(Me.Label1)

Me.Controls.Add(Me.ListBox1)

Me.Controls.Add(Me.txtIterations)

Me.Controls.Add(Me.btnStart)

Me.Name = "Form3"

Me.Text = "Form3"

Me.ResumeLayout(False)

End Sub

#End Region

Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

Try

'Dim mVoiceBocx1 As VoiceBocxLib.VoiceBocx

'mVoiceBocx1 = New VoiceBocxLib.VoiceBocx

'iNrTrunks =
mVoiceBocx1.GetInstalledChannels(VoiceBocxLib.RES_ TYPE.RES_TYPE_Trunk)

'mVoiceBocx1 = Nothing

Catch ex As Exception

Trace("Error getting installed trunks =" & ex.Message)

Return

End Try

Trace("There are " & iNrTrunks & " trunks available")

End Sub

Public Sub Trace(ByVal Text As String)

If (ListBox1.Items.Count > 800) Then

ListBox1.Items.RemoveAt(0)

End If

ListBox1.Items.Add(Text)

ListBox1.SelectedIndex = ListBox1.Items.Count - 1

End Sub

Private Sub btnLaunchThread_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnStart.Click

Dim iTrunk As Integer

Dim iToTrunk As Integer

Dim iFromTrunk As Integer

Trace("Starting threads to service trunks")

iToTrunk = ToTrunk.Text

iFromTrunk = FromTrunk.Text

If (iToTrunk > iNrTrunks - 1) Then

Trace("Last trunk to use changed to last available")

iToTrunk = iNrTrunks - 1

ToTrunk.Text = iToTrunk 'don't start more trunks then we have

ToTrunk.Invalidate()

End If

If (iFromTrunk > iToTrunk) Then

Trace("First trunk to use changed to last requested")

iFromTrunk = iToTrunk

FromTrunk.Text = iFromTrunk 'don't start more trunks then we have

FromTrunk.Invalidate()

End If

'Allocate array of LineHandler objects to keep track of

'lines so that we can shut them down properly.

'It is a good practice to check if "new" succeeded but

'it is not done here for simplicity.

ReDim LineArray(iToTrunk - iFromTrunk)

Dim Line As New TrunkThread

For iTrunk = iFromTrunk To iToTrunk

Line = New TrunkThread

LineArray(iTrunk - iFromTrunk) = Line

'pass parameters to the new thread

Line.iTrunk = iTrunk

Line.MainForm = Me

'this delegate will handle thread start event

Dim ts As ThreadStart

ts = New ThreadStart(AddressOf Line.main)

'create new thread

Dim wrkThread As Thread

wrkThread = New Thread(ts)

Line.CurrentThread = wrkThread

Trace("Starting new thread for trunk " & iTrunk)

wrkThread.ApartmentState = ApartmentState.STA 'default is MTA

wrkThread.Name = iTrunk.ToString() 'for easier tracing

wrkThread.IsBackground = True

wrkThread.Start()

Next

btnStart.Enabled = False

End Sub

Private Sub ButtonExit_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnExit.Click

'We must not exit if the call is in progress, need to check it in
Form.Closing

Close() 'Closing event for the Form is not triggered without this

End Sub

'validate from/to trunk values

Private Sub Trunk_KeyPress_From(ByVal sender As Object, ByVal e As
KeyPressEventArgs) Handles FromTrunk.KeyPress

'If not numeric, tell Windows that we handled the event.

'Backspace is allowed for corrections.

If (Not (Char.IsNumber(e.KeyChar)) And (e.KeyChar <> ChrW(8))) Then '8 is
backspace

e.Handled = True

End If

End Sub

Private Sub Trunk_KeyPress_To(ByVal sender As Object, ByVal e As
KeyPressEventArgs) Handles ToTrunk.KeyPress

'If not numeric, tell Windows that we handled the event.

'Backspace is allowed for corrections.

If (Not (Char.IsNumber(e.KeyChar)) And (e.KeyChar <> ChrW(8))) Then '8 is
backspace

e.Handled = True

End If

End Sub

Private Sub MTInboundForm_Closed(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Closed

Application.Exit()

End Sub

Private Sub MTInboundForm_Closing(ByVal sender As System.Object, ByVal e As
CancelEventArgs) Handles MyBase.Closing

e.Cancel = False 'don't cancel exit

'if lines never started

If (LineArray Is Nothing) Then

Return

End If

Dim iLineCount As Integer = LineArray.Length

Do

Dim iStillRunning As Integer = 0

Dim iLine As Integer = 0

For iLine = 0 To iLineCount - 1

'if thread already exited, continue

If (Not ((LineArray(iLine).CurrentThread) Is Nothing)) Then

LineArray(iLine).Shutdown(False)

If (Not ((LineArray(iLine).CurrentThread) Is Nothing)) Then

iStillRunning = iStillRunning + 1

End If

End If

Next

If (0 = iStillRunning) Then 'we are done

Return

End If

Dim strMsg As String = "There are still " + Str(iStillRunning) + " running
threads."

Dim Result As DialogResult = MessageBox.Show( _

strMsg + " Do you want to try again (No will force the exit as is)?", _

"Exiting Application", MessageBoxButtons.YesNo)

If (DialogResult.No = Result) Then

'force exit even if some threads not stopped yet

For iLine = 0 To iLineCount - 1

If (Not ((LineArray(iLine).CurrentThread) Is Nothing)) Then

LineArray(iLine).Shutdown(True) 'force exit

End If

Next

Return 'we are done

End If

Loop While (True)

End Sub

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

'LineArray(txtCallOutOn.Text).bcallout = True

LineArray(txtCallOutOn.Text).callout()

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button2.Click

LineArray(txtCallOutOn.Text).conf(txtBridge.Text)

LineArray(txtBridge.Text).conf(txtCallOutOn.Text)

End Sub

End Class

Class TrunkThread

'Public WithEvents mVoiceBocx As VoiceBocxLib.VoiceBocx ' VoiceBocx control

Public MainForm As Form3

Public iTrunk As Integer

Public bcallout As Boolean

Public CurrentThread As Thread

Private bincall As Boolean

Public Property test()

Get

End Get

Set(ByVal Value)

End Set

End Property

Public Sub main()

Dim iThreadId As Integer

iThreadId = Thread.CurrentThread.GetHashCode()

MainForm.Trace("In the new thread " & iThreadId & " on trunk " & iTrunk)

Try

'mVoiceBocx = New VoiceBocxLib.VoiceBocx

MainForm.Trace("Voice Object instantiated on trunk " & iTrunk)

'mVoiceBocx.TrunkAssign(iTrunk)

MainForm.Trace("Trunk assigned " & iTrunk)

Catch e As COMException

MainForm.Trace("Error starting Voice Object =" & (e.ErrorCode And 65535))

Return

Catch e As Exception

MainForm.Trace("Error using Voice Object =" & e.Message)

Return

End Try

MainForm.Trace("Incoming call handler set on trunk " & iTrunk)

Application.Run()

End Sub

Public Sub callout()

MainForm.Trace("OutDial for trunk " & iTrunk)

Try

'mVoiceBocx.MakeCall("474-7031", True)

MainForm.Trace("Playing greeting on trunk " & iTrunk)

'mVoiceBocx.PlayFile("hello.vox",
VoiceBocxLib.SOUNDFILE_TYPE.SOUNDFILE_TYPE_Vox24K)

Do

Thread.CurrentThread.Sleep(100)

Loop

Catch e As COMException

Dim iCode As Integer

iCode = e.ErrorCode And 65535

'If (mVoiceBocx.ErrorNumber = iCode) Then

'MainForm.Trace("Hangup detected on trunk " & iTrunk)

'Else

' MainForm.Trace("Call processing ended with code " & iCode)

'End If

Finally

Try

MainForm.Trace("Disconnecting on trunk " & iTrunk)

'mVoiceBocx.DisconnectCall()

Catch e As COMException

MainForm.Trace("Exception " & (e.ErrorCode And 65535) & "on trunk " &
iTrunk)

End Try

bincall = False

MainForm.Trace("Ready for calls on trunk " & iTrunk)

End Try

End Sub

Public Sub conf(ByVal iWho As Integer)

MainForm.Trace("Conf for trunk " & iTrunk)

Try

'mVoiceBocx.TrunkListenTo(VoiceBocxLib.RES_TYPE.RE S_TYPE_Trunk, iWho)

MainForm.Trace("Conf " & iTrunk & " and " & iWho)

Do

Thread.CurrentThread.Sleep(100)

Loop

Catch e As COMException

Dim iCode As Integer

iCode = e.ErrorCode And 65535

'If (mVoiceBocx.ErrorNumber = iCode) Then

'MainForm.Trace("Hangup detected on trunk " & iTrunk)

'Else

' MainForm.Trace("Call processing ended with code " & iCode)

'End If

Finally

Try

MainForm.Trace("Disconnecting on trunk " & iTrunk)

'mVoiceBocx.DisconnectCall()

Catch e As COMException

MainForm.Trace("Exception " & (e.ErrorCode And 65535) & "on trunk " &
iTrunk)

End Try

bincall = False

MainForm.Trace("Ready for calls on trunk " & iTrunk)

End Try

End Sub

Public Sub Shutdown(ByVal bForceExit As Boolean)

If (bincall And (False = bForceExit)) Then

Return

End If

'mVoiceBocx.TrunkUnassign()

'mVoiceBocx.MediaUnassign()

CurrentThread.Abort()

CurrentThread = Nothing

End Sub

Private Sub mVoiceBocx_IncomingCall() 'Handles mVoiceBocx.IncomingCall

bincall = True

Try

MainForm.Trace("Rings for trunk " & iTrunk)

'mVoiceBocx.AnswerCall()

MainForm.Trace("Playing greeting on trunk " & iTrunk)

'mVoiceBocx.PlayFile("hello.vox",
VoiceBocxLib.SOUNDFILE_TYPE.SOUNDFILE_TYPE_Vox24K)

Do

Thread.CurrentThread.Sleep(100)

Loop

Catch e As COMException

Dim iCode As Integer

iCode = e.ErrorCode And 65535

'If (mVoiceBocx.ErrorNumber = iCode) Then

'MainForm.Trace("Hangup detected on trunk " & iTrunk)

'Else

' MainForm.Trace("Call processing ended with code " & iCode)

'End If

Finally

Try

MainForm.Trace("Disconnecting on trunk " & iTrunk)

'mVoiceBocx.DisconnectCall()

Catch e As COMException

MainForm.Trace("Exception " & (e.ErrorCode And 65535) & "on trunk " &
iTrunk)

End Try

bincall = False

MainForm.Trace("Ready for calls on trunk " & iTrunk)

End Try

End Sub 'incoming call

Private Sub mVoiceBocx_CallerHangUp() 'Handles mVoiceBocx.CallerHangUp

MainForm.Trace("Caller hungup " & iTrunk)

End Sub

End Class
Nov 21 '05 #1
Share this Question
Share on Google+
3 Replies


P: n/a
After a quick glance, it appears as if you have an endless loop. You
have these lines of code in the callout function:

Do
Thread.CurrentThread.Sleep(100)
Loop

It will never exit that loop. Secondly, you appear to be calling back
into the main form from the thread. This is also not a good idea, and
the Windows forms controls are not thread safe. At the end of this
post, I added a small class that you can use to create derived classes
that run in their own thread. The thread wrapper class just
encapsulates a thread and make it easy to create classes that run on
that thread.

We tried using VoiceBocx with your approach but utimately decided on a
different approach. We wrote it so that each line basically ran in a
loop on a separate thread. In the loop the thread would check a "call
queue" to see if there were any calls to be made. If so, they would
remove the call record from the queue and make the call. They would
then store the call progress results to a separate results queue.
There was a single thread running that would process that queue.

We used a single queue to service all lines on the application, but if
you have a small number of lines, you could have a separate queue for
each line, but whatever process fills the queues would have to have
some sort of distribution logic so that all lines would keep busy.

Basically we had a thread that would query the database or file for the
phone numbers to be called. These would be placed on a call queue.

Each vbocx line would run on its own thread in a loop until told to
stop. The loop would check the queue to see if there were any calls to
make. If so, it would grab a call from the queue and make the call and
deliver the message. It would then place the call progress result
(Busy, No Answer, etc) on a result queue. If there were no calls on
the queue to be made, the Vbocx thread would wait for a short time for
any inbound calls, it would then repeat the loop.

There was another thread whose job was to process the items in the
result queue and update the database with the results.
Here is a class that you derive your TrunkThread from that makes it
easy to start a line on a thread. Although it is simple, you could
modify it if necessary. To use it, you derive your class from it like
this:

Public Class TrunkThread
Inherits ThreadWrapperBase

Protected Overrides Sub Execute()
'This is where you would put the loop of execution of the
thread
'For example:

Do
'Get call to make from database or call queue
'Make call and Deliver message if answered
'Store results of call on call result queue or in
database
'Monitor line for an incoming call
Loop Until bStopProcessing
End Sub

End Class

Then to use it and start your thread, you would use code like this:

Dim MyTrunkThread As New TrunkThread
MyTrunkThread.Start
'ThreadWrapperBase class
Public MustInherit Class ThreadWrapperBase

'Our thread object
Public ReadOnly Thread As System.Threading.Thread

Public Sub New()
'Create the thread
Me.Thread = New System.Threading.Thread(AddressOf
Me.StartThread)
End Sub

'Starts execution of the thread
Public Overridable Sub Start()
Me.Thread.Start()
End Sub

'Aborts the thread. this sub can be overridden to kill the thread
more gracefully
Public Overridable Sub [Stop]()
Me.Thread.Abort()
End Sub

'Property to indicate the thread is completed
Private m_IsCompleted As Boolean
Public ReadOnly Property IsCompleted() As Boolean
Get
Return m_IsCompleted
End Get
End Property

'When the thread is started, this is the sub that is called, it in
turn calls the Execute method which
'derived classes must override.
Private Sub StartThread()
m_IsCompleted = False
Execute()
m_IsCompleted = True
End Sub

'This is the sub that performs the "work" of the thread. It must
be overridden in the derived class
Protected MustOverride Sub Execute()

End Class

Nov 21 '05 #2

P: n/a
Greetings Chris!!

Thanks for the reply...

I simply have the thread.currentthread.sleep(100) in there to basically sit
and wait after making the callout, because we are then going to conference
this thread / trunk with an inbound call thread.

I had the basic threads started, all where running with application.run
which means they would jump to the INBOUNDCALL event when the voicebocx
received a call, I was then attempting to trigger the outbound call with a
button on the main form (this is all for testing at this point), and this is
where the blocking occurred.

I then changed the main thread, so that instead of calling APPLICATION.RUN
to startup the messaging queue, that it sat in a loop doing the following

While True
Thread.CurrentThread.Sleep(100)
If bcallout = True Then
RaiseEvent CallOut(iTrunk)
End If
if mvoicebocx.trunkstate=whatever the inboundcalling state was then
RaiseEvent InboundCall()
end if
End While

As surprisingly considering that the mvoicebocx was declared withevents the
regular INBOUNDCALL event was never triggered... but in this loop
methodology the trunkstate never amounts to a ringing call either.....

Very confusing....

"Chris Dunaway" <du******@gmail.com> wrote in message
news:11*********************@l41g2000cwc.googlegro ups.com...
After a quick glance, it appears as if you have an endless loop. You
have these lines of code in the callout function:

Do
Thread.CurrentThread.Sleep(100)
Loop

It will never exit that loop. Secondly, you appear to be calling back
into the main form from the thread. This is also not a good idea, and
the Windows forms controls are not thread safe. At the end of this
post, I added a small class that you can use to create derived classes
that run in their own thread. The thread wrapper class just
encapsulates a thread and make it easy to create classes that run on
that thread.

We tried using VoiceBocx with your approach but utimately decided on a
different approach. We wrote it so that each line basically ran in a
loop on a separate thread. In the loop the thread would check a "call
queue" to see if there were any calls to be made. If so, they would
remove the call record from the queue and make the call. They would
then store the call progress results to a separate results queue.
There was a single thread running that would process that queue.

We used a single queue to service all lines on the application, but if
you have a small number of lines, you could have a separate queue for
each line, but whatever process fills the queues would have to have
some sort of distribution logic so that all lines would keep busy.

Basically we had a thread that would query the database or file for the
phone numbers to be called. These would be placed on a call queue.

Each vbocx line would run on its own thread in a loop until told to
stop. The loop would check the queue to see if there were any calls to
make. If so, it would grab a call from the queue and make the call and
deliver the message. It would then place the call progress result
(Busy, No Answer, etc) on a result queue. If there were no calls on
the queue to be made, the Vbocx thread would wait for a short time for
any inbound calls, it would then repeat the loop.

There was another thread whose job was to process the items in the
result queue and update the database with the results.
Here is a class that you derive your TrunkThread from that makes it
easy to start a line on a thread. Although it is simple, you could
modify it if necessary. To use it, you derive your class from it like
this:

Public Class TrunkThread
Inherits ThreadWrapperBase

Protected Overrides Sub Execute()
'This is where you would put the loop of execution of the
thread
'For example:

Do
'Get call to make from database or call queue
'Make call and Deliver message if answered
'Store results of call on call result queue or in
database
'Monitor line for an incoming call
Loop Until bStopProcessing
End Sub

End Class

Then to use it and start your thread, you would use code like this:

Dim MyTrunkThread As New TrunkThread
MyTrunkThread.Start
'ThreadWrapperBase class
Public MustInherit Class ThreadWrapperBase

'Our thread object
Public ReadOnly Thread As System.Threading.Thread

Public Sub New()
'Create the thread
Me.Thread = New System.Threading.Thread(AddressOf
Me.StartThread)
End Sub

'Starts execution of the thread
Public Overridable Sub Start()
Me.Thread.Start()
End Sub

'Aborts the thread. this sub can be overridden to kill the thread
more gracefully
Public Overridable Sub [Stop]()
Me.Thread.Abort()
End Sub

'Property to indicate the thread is completed
Private m_IsCompleted As Boolean
Public ReadOnly Property IsCompleted() As Boolean
Get
Return m_IsCompleted
End Get
End Property

'When the thread is started, this is the sub that is called, it in
turn calls the Execute method which
'derived classes must override.
Private Sub StartThread()
m_IsCompleted = False
Execute()
m_IsCompleted = True
End Sub

'This is the sub that performs the "work" of the thread. It must
be overridden in the derived class
Protected MustOverride Sub Execute()

End Class

Nov 21 '05 #3

P: n/a
I think we have it all figured out!!!

Thanks CHRIS!!! That was an IMMENSE HELP!!!!!!!!!!

Where do I send the KUDOS???

"Chris Dunaway" <du******@gmail.com> wrote in message
news:11*********************@l41g2000cwc.googlegro ups.com...
After a quick glance, it appears as if you have an endless loop. You
have these lines of code in the callout function:

Do
Thread.CurrentThread.Sleep(100)
Loop

It will never exit that loop. Secondly, you appear to be calling back
into the main form from the thread. This is also not a good idea, and
the Windows forms controls are not thread safe. At the end of this
post, I added a small class that you can use to create derived classes
that run in their own thread. The thread wrapper class just
encapsulates a thread and make it easy to create classes that run on
that thread.

We tried using VoiceBocx with your approach but utimately decided on a
different approach. We wrote it so that each line basically ran in a
loop on a separate thread. In the loop the thread would check a "call
queue" to see if there were any calls to be made. If so, they would
remove the call record from the queue and make the call. They would
then store the call progress results to a separate results queue.
There was a single thread running that would process that queue.

We used a single queue to service all lines on the application, but if
you have a small number of lines, you could have a separate queue for
each line, but whatever process fills the queues would have to have
some sort of distribution logic so that all lines would keep busy.

Basically we had a thread that would query the database or file for the
phone numbers to be called. These would be placed on a call queue.

Each vbocx line would run on its own thread in a loop until told to
stop. The loop would check the queue to see if there were any calls to
make. If so, it would grab a call from the queue and make the call and
deliver the message. It would then place the call progress result
(Busy, No Answer, etc) on a result queue. If there were no calls on
the queue to be made, the Vbocx thread would wait for a short time for
any inbound calls, it would then repeat the loop.

There was another thread whose job was to process the items in the
result queue and update the database with the results.
Here is a class that you derive your TrunkThread from that makes it
easy to start a line on a thread. Although it is simple, you could
modify it if necessary. To use it, you derive your class from it like
this:

Public Class TrunkThread
Inherits ThreadWrapperBase

Protected Overrides Sub Execute()
'This is where you would put the loop of execution of the
thread
'For example:

Do
'Get call to make from database or call queue
'Make call and Deliver message if answered
'Store results of call on call result queue or in
database
'Monitor line for an incoming call
Loop Until bStopProcessing
End Sub

End Class

Then to use it and start your thread, you would use code like this:

Dim MyTrunkThread As New TrunkThread
MyTrunkThread.Start
'ThreadWrapperBase class
Public MustInherit Class ThreadWrapperBase

'Our thread object
Public ReadOnly Thread As System.Threading.Thread

Public Sub New()
'Create the thread
Me.Thread = New System.Threading.Thread(AddressOf
Me.StartThread)
End Sub

'Starts execution of the thread
Public Overridable Sub Start()
Me.Thread.Start()
End Sub

'Aborts the thread. this sub can be overridden to kill the thread
more gracefully
Public Overridable Sub [Stop]()
Me.Thread.Abort()
End Sub

'Property to indicate the thread is completed
Private m_IsCompleted As Boolean
Public ReadOnly Property IsCompleted() As Boolean
Get
Return m_IsCompleted
End Get
End Property

'When the thread is started, this is the sub that is called, it in
turn calls the Execute method which
'derived classes must override.
Private Sub StartThread()
m_IsCompleted = False
Execute()
m_IsCompleted = True
End Sub

'This is the sub that performs the "work" of the thread. It must
be overridden in the derived class
Protected MustOverride Sub Execute()

End Class

Nov 21 '05 #4

This discussion thread is closed

Replies have been disabled for this discussion.