Click to See Complete Forum and Search --> : Mutex(?) question
gpser
June 10th, 2002, 07:51 PM
I am using VB.NET and want to coordinate two threads. Each thread can write to the serial port, but I need to make sure when this happens that a single thread can complete a series of writes before the other starts (in other words, a complete and consistent block of data is written without being interpersed with data from the other thread. Should be easy using thread communications, but the documentation is pretty fuzzy. Can anyone provide a simple example where threads can mutually block each other to support this kind of communication? There appear to be several ways to do this (synclock on an object, waithandles, etc.), but the ramifications of one ver. another is not apparent. My needs should be pretty simple.
Thanks
Al
softweng
June 14th, 2002, 09:41 AM
This is how I have done it in the past and it worked great.
Private Sub WriteToSerialPort(ByVal Data() As Byte)
Dim CurrThread As Thread
'//Get A Reference To The Calling Thread
CurrThread = Thread.CurrentThread
'//Block All Other Calling Threads
SyncLock CurrThread
'//Write To Serial Port And What Ever Else That Needs Done
End SyncLock
End Sub
gpser
June 14th, 2002, 03:39 PM
Kris-
Thanks for the suggestion. I built a little ap to test your approach and discovered it doesn't work quite right (I think???). I believe there's a problem with locking on an object within a procedure called from multiple threads. Each thread will use a new call to the procedure which will create a new instance of the lock object. The result is no lock at all! To fix this, move the lock object up to higher-level scope.
I was having so much fun with this, I wanted to share the little ap I made if anyone else wants to play with threading/mutex. Notice that I also used a simpler object for the synclock. I think any object at all will do, so I picked a simpler one than you used. Do you think it matters?
The attached file is a small ap that show how to create new threads and how to lock access to a section of code to ensure that only a single thread at a time can execute the code. I also illustrated a few other principles like thread priority and inter-task signalling.
I did run across a problem with the debugger. If I break on the sub OneAtATime and try to single step into it, the debuger will NOT step past the synclock. It just hangs there. Anyone else see this??
Kris-I left your suggested way in but commented it out in case you want to try it. I'm new to .NET threading, so any comments are welcome!!!
Cheers
Al
gpser
June 14th, 2002, 03:47 PM
I tried to "attach" code to the prior message, but it doesn't seem to work. Why is .VB not a valid file extension. Anyway, here it is the kludgy way (I'll figure out how to do it right next time):
Option Strict On
Option Explicit On
Imports System.Threading
Public Class Test
Inherits System.Windows.Forms.Form
Private Lock(0) As Integer 'Has to be a reference type for SyncLock
Private Released As Boolean
Private T1AREvent As New AutoResetEvent(False)
Private T2AREvent As New AutoResetEvent(False)
Private Thread1 As Thread
Private Thread2 As Thread
#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 TName As System.Windows.Forms.TextBox
Friend WithEvents Launch1 As System.Windows.Forms.Button
Friend WithEvents Launch2 As System.Windows.Forms.Button
Friend WithEvents Release As System.Windows.Forms.Button
Friend WithEvents Both As System.Windows.Forms.Button
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.TName = New System.Windows.Forms.TextBox()
Me.Launch1 = New System.Windows.Forms.Button()
Me.Launch2 = New System.Windows.Forms.Button()
Me.Release = New System.Windows.Forms.Button()
Me.Both = New System.Windows.Forms.Button()
Me.SuspendLayout()
'
'TName
'
Me.TName.Location = New System.Drawing.Point(24, 16)
Me.TName.Name = "TName"
Me.TName.Size = New System.Drawing.Size(64, 20)
Me.TName.TabIndex = 0
Me.TName.Text = ""
'
'Launch1
'
Me.Launch1.Location = New System.Drawing.Point(24, 56)
Me.Launch1.Name = "Launch1"
Me.Launch1.Size = New System.Drawing.Size(64, 23)
Me.Launch1.TabIndex = 1
Me.Launch1.Text = "Launch1"
'
'Launch2
'
Me.Launch2.Location = New System.Drawing.Point(24, 88)
Me.Launch2.Name = "Launch2"
Me.Launch2.Size = New System.Drawing.Size(64, 23)
Me.Launch2.TabIndex = 2
Me.Launch2.Text = "Launch2"
'
'Release
'
Me.Release.Location = New System.Drawing.Point(24, 152)
Me.Release.Name = "Release"
Me.Release.Size = New System.Drawing.Size(64, 23)
Me.Release.TabIndex = 3
Me.Release.Text = "Release"
'
'Both
'
Me.Both.Location = New System.Drawing.Point(25, 120)
Me.Both.Name = "Both"
Me.Both.Size = New System.Drawing.Size(64, 23)
Me.Both.TabIndex = 4
Me.Both.Text = "Both"
'
'Test
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(115, 198)
Me.Controls.AddRange(New System.Windows.Forms.Control() {Me.Both, Me.Release, Me.Launch2, Me.Launch1, Me.TName})
Me.Name = "Test"
Me.ResumeLayout(False)
End Sub
#End Region
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Thread1 = New Thread(New ThreadStart(AddressOf Task1))
Thread1.Name = "Task1"
Thread1.Priority = ThreadPriority.Highest
Thread1.IsBackground = True 'Set to background so it's automatically killed.
Thread2 = New Thread(New ThreadStart(AddressOf Task2))
Thread2.Name = "Task2"
Thread2.Priority = ThreadPriority.Lowest
Thread2.IsBackground = True 'Set to background so it's automatically killed.
Thread.CurrentThread.Name = "Default VB Thread" 'So it's easy to spot in Thread debug window
Released = False
TName.Text = ""
Thread1.Start()
Thread2.Start()
End Sub
Private Sub Task1()
While (True)
'T1AREvent.Reset()
T1AREvent.WaitOne()
OneAtATime()
End While
End Sub
Private Sub Task2()
While (True)
'T2AREvent.Reset()
T2AREvent.WaitOne()
OneAtATime()
End While
End Sub
Private Sub OneAtATime()
''''Dim CurrThread As Thread
''''CurrThread = Thread.CurrentThread 'Get A Reference To The Calling Thread
''''SyncLock CurrThread 'Block All Other Calling Threads
SyncLock Lock
'Critical section follows
TName.Text = Thread.CurrentThread.Name
While Not Released
Thread.CurrentThread.Sleep(50) 'Wait 50mSec
End While
TName.Text = ""
Released = False
End SyncLock
End Sub
Private Sub Launch1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Launch1.Click
T1AREvent.Set() 'Kick off Task1
End Sub
Private Sub Launch2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Launch2.Click
T2AREvent.Set() 'Kick off Task2
End Sub
Private Sub Both_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Both.Click
If Int(DateAndTime.Timer) Mod 2 = 1 Then 'A pseudorandomizer
T1AREvent.Set() 'Kick off Task1
T2AREvent.Set() 'Kick off Task2
Else
T2AREvent.Set() 'Kick off Task2
T1AREvent.Set() 'Kick off Task1
End If
End Sub
Private Sub Release_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Release.Click
Released = True
End Sub
End Class
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.