Can't figure out why ArrayList.RemoveAt() is not working - vb.net

I am currently using Florian Leitner's HID USB library in my VB.NET solution for communicating with a pin pad. As per his sample code, I set up an event handler to handle incoming responses from the device which are stored in an ArrayList called usbBuffer:
Private Sub BufferEventHandler(ByVal sender As Object, ByVal e As System.EventArgs)
If USBInterface.usbBuffer.Count > 0 Then
While USBInterface.usbBuffer(0) Is Nothing
SyncLock USBInterface.usbBuffer.SyncRoot
USBInterface.usbBuffer.RemoveAt(0)
End SyncLock
End While
_receiveArray = CType(USBInterface.usbBuffer(0), Byte())
_usbInterface.stopRead()
SyncLock USBInterface.usbBuffer.SyncRoot
USBInterface.usbBuffer.RemoveAt(0)
End SyncLock
End If
End Sub
The problem is that the RemoveAt is not working, since the first element in the list remains there after the handler is done. Could someone please advise as to what I've done wrong, or perhaps use a different approach?

msdn says that the object of the synclock cannot be nothing.
and you cannot cjhange the value of the lockobject.
msdn http://msdn.microsoft.com/en-us/library/3a86s51t(VS.80).aspx says
Rules
Lock Object Value. The value of lockobject cannot be Nothing. You must create the lock object before you use it in a SyncLock statement.
You cannot change the value of lockobject while executing a SyncLock block. The mechanism requires that the lock object remain unchanged.

Related

VB.Net Multi-Threading InvokeRequired and Passing Thread

I need to be able to pass the thread name into a subroutine in order to abort it when I need to.
So I have this so far:
Dim BrowserSpawn As New System.Threading.Thread(AddressOf BrowserSub)
BrowserSpawn.Start()
Private Async Sub BrowserSub(BrowserSpawn)
...
End Sub
Because the subroutine creates a browser within Form1 groups I needed to invoke access to these controls within the sub.
Note: This works fine when I'm not passing in the thread name.
If Me.GroupNamehere.InvokeRequired Then
Me.GroupNamehere.Invoke(New MethodInvoker(AddressOf BrowserSub))
Else
'Do nothing
End If
When I'm passing in the thread name these become a problem when trying to compile:
Method does not have a signature compatible with delegate 'Delegate Sub MethodInvoker()'.
I'm hoping this is just a syntax thing but I can't seem to get it to work. Is there any way I'm able to pass in this thread name without breaking my invokerequired check?
If I try and change it to the obvious:
Me.GroupNamehere.Invoke(New MethodInvoker(AddressOf BrowserSub(BrowserSpawn)))
It tells me Addressof operand must be the name of a method (without parentheses). Although without the parentheses it's not happy either so I don't know where to go from here.
/edit:
Stumbled across How can I create a new thread AddressOf a function with parameters in VB?
Which seems to confirm what I was trying passing something like:
Private Sub test2(Threadname As Thread)
' Do something
End Sub
And the sub seems happy with that. But I'm not sure how to do that without breaking the invoker part.
Me.GroupNameHere.Invoke(New MethodInvoker(AddressOf SubNameHere))
Works normally. If SubNameHere() becomes SubNameHere(threadname as thread) then that seems happy enough but the invoke line breaks and doesn't want more than the address of.
Two slight syntax changes sorted it:
Private Async Sub SubName(ThreadNameAs Thread)
and
GroupName.Invoke(New MethodInvoker(Sub() Me.SubName(ThreadName)))

Is double synclock within the same thread ok?

I have a situation where multiple threads may access a class, the class consists of 3 private values and 6 properties that get/set various arithmetic combinations of the 3 values. Then I have 6 more properties that are just type conversions as they call on the first 6 properties as a part of their get/set operation.
All the get/set functions of the first 6 properties are synclocked to the same object. I wanted to synclock the get/set functions of the other 6 too to the same object since they use some of the same utility objects but it occurred to me that this will lead to synclocking the same object twice in a row.. sorta like this:
Private lock As New Object
Private _dCool As Double
Public Property dCool As Double
Get
SyncLock lock
Return _dCool
End SyncLock
End Get
Set(value As Double)
SyncLock lock
_dCool = value
End SyncLock
End Set
End Property
Public Property iCool As Integer
Get
SyncLock lock
Return dCool
End SyncLock
End Get
Set(value As Integer)
SyncLock lock
dCool = value
End SyncLock
End Set
End Property
There is no need to synclock iCool in this example but its just to illustrate the problem. As far as I've tested, there seem to be no problems with this but just wanted to ask if some problems i cant see right now could come up by doing this?
Yes, not a problem. The VB.NET compiler generates calls to Monitor.Enter/Exit() when you use the SyncLock keyword, along with Try/Finally blocks to ensure that the entered monitor is always exited. The MSDN article for Monitor.Enter says:
It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.
Relevant phrase bolded. The Finally block ensure that the Exit() call requirement is always met.

How to safely access a global variable from a backgroundworker thread vb.net

I've got a backgroundworker implemented in my program and it's accessing a global variable decalred outside the thread. IT causes no errors but setting the checkillegalstring property and there are cross thread exceptions all over the place. I found out that it's because it's using the global variable I've declared previously.
I can't seem to find anywhere that I can use a global variable inside my backgroundworker thread, is this possible to do?
The simplest way is with SyncLock
Sub firstNewThread()
SyncLock objLock
'Access global object
End SyncLock
End Sub
Sub secondNewThread()
SyncLock objLock
'Guaranteed to not be executing while block in first thread is running
End SyncLock
End Sub
Just be aware of other pitfalls like deadlocks that may occur from this.
Perhaps you can try SyncLock.
See this answer: https://stackoverflow.com/a/915877/153923
For example:
// C#
lock (someLock)
{
list.Add(someItem);
}
// VB
SyncLock someLock
list.Add(someItem)
End SyncLock

Appending text to a richTextBox in a different thread and code file

With the intention of creating a program to interface with a serial port device, I recently started learning vb.net. To keep the structure neat the vb code has been split into two places; the first is the code behind for initialising, clicking buttons etc., whilst the second is for managing the comm port. Respectively, these are named 'MainWindow.xaml.vb' and 'ComPortManager.vb'.
In 'comPortManager.vb':
Dim RXArray(2047) As Char ' Array to hold received characters
Dim RXCnt As Integer ' Received character count
Private Sub comPort_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles comPort.DataReceived
Do
RXCnt = 0
Do
'Populates the array, RXArray and counts the number of characters, RXCnt
Loop Until (comPort.BytesToRead = 0) 'Keeps reading the buffer until it is empty
'Code for posting to the richTextBox
Loop Until (comPort.BytesToRead = 0) 'If the buffer has been written to in the meantime, repeat
End Sub
The 'MainWindow.xaml' contains a ribbon (Microsoft's October 2010 release) with controls for settings, opening, closing and sending (keeping it all separate and simple for now), with the rest of the window being a richTextBox entitled 'RichTextBox1'.
The search for a way to post the contents of RXArray to RichTextBox1 brought up many suggestions based around Invoke or BeginInvoke. Indeed, working examples have been run successfully but all the code associated with Invoke has been in one file, the code behind. (Correct me if I'm wrong, but this sounds fine for small programs but could get bloated with medium to larger programs, hence me wanting to find a better solution)
The code closest to running (I believe) is as follows:
'In comPort_DataReceived... after populating the array
If RichTextBox1.InvokeRequired Then
RichTextBox1.Invoke(New MethodInvoker(AddressOf Display))
End If
'and back in the main code
Public Delegate Sub MethodInvoker()
Private Sub Display()
RichTextBox1.AppendText(New String(RXArray, 0, RXCnt))
End Sub
This has a few problems and I'm not sure in what direction to go at this stage. RichTextBox1 is in a different thread hence not recognised; InvokeRequired is not a member of System.Windows.Controls.RichTextBox, likewise with Invoke; and finally, in examples, the delegate entitled MethodInvoker was never stated as above.
Any help on this topic is most appreciated. In these few weeks, Invoke, BeginInvoke etc. have somewhat eluded my comprehension. Regards, Jonathan
we have a large scale application which a textbox has the status of many threads appended to it concurrently, and from different forms. this is a dumbed down version of it:
Public Sub addToMessageBox(ByVal msg As String)
If Me.InvokeRequired Then
Dim d As New AddToMessageBoxDelegate(AddressOf Me.addToMessageBox)
Me.BeginInvoke(d, New Object() {msg})
Else
Try
Me.MessageBox.AppendText("--" + msg + vbCrLf)
Catch ex As Exception
End Try
End If
End Sub
The delegate is declared at the begining
Private Delegate Sub AddToMessageBoxDelegate(ByVal msg As String)
the biggest difference that I can see is that I use the parent class's beginInvoke() and InvokeRequired(). I'd say give this a try. Call the parentClass.AddToMessageBox("Text you want to append") where you are calling the display().

What should I SyncLock in this code, and where?

I have a class that has two method in it, one calls a class which creates and executes a number of threads, the other is an event handler that handles an event raised when those threads complete (and then calls the first method again).
I understand that the method that handles the event runs in the thread that raised the event. So as such, I SyncLock a member variable that says how many threads are running and subtract one from it:
SyncLock Me ' GetType(me)
_availableThreads -= 1
End SyncLock
So I have a few questions:
Main Question: Should I be SyncLock'ing _availableThreads everywhere in the class - i.e in the method that creates the threads (which adds 1 when a thread is created)
Side Questions related to this question:
I'd usually SyncLock the current instance, but I've seen code that SyncLocks the type instead, so what is the difference between sync locking Me (Current Instance) and GetType(Me)?
Would there be a performance difference between the two? and is there anything smaller I'd be able to lock for the above that doesn't affect anything else - perhaps a separate 'padlock' object created for the sole purpose of locking things within a class?
Note: The sole purpose of _availableThreads is to control how many threads can run at any given time and the threads process jobs that can take hours to run.
Code:
Public Class QManager
Private _maxThreadCount, _availableThreads As Integer
Public Sub New(ByVal maxThreadCount As Integer)
Me.MaximumThreadCount = maxThreadCount
End Sub
Public Sub WorkThroughQueue()
//get jobs from queue (priorities change, so call this every time)
Dim jobQ As Queue(Of QdJobInfo) = QueueDAO.GetJobList
//loop job queue while there are jobs and we have threads available
While jobQ.Count > 0 And _availableThreads <= _maxThreadCount
//create threads for each queued job
Dim queuedJob As New QdJob(jobQ.Dequeue)
AddHandler queuedJob.ThreadComplete, AddressOf QueuedJob_ThreadCompleted
_availableThreads += 1 //use a thread up (do we need a sync lock here?)***************************
queuedJob.Process() //go process the job
End While
//when we get here, don't do anything else - when a job completes it will call this method again
End Sub
Private Sub QueuedJob_ThreadCompleted(ByVal sender As QdJobInfo, ByVal args As EventArgs)
SyncLock Me //GetType(me)
_availableThreads -= 1
End SyncLock
//regardless of how the job ended, we want to carry on going through the rest of the jobs
WorkThroughQueue()
End Sub
#Region "Properties"
Public Property MaximumThreadCount() As Integer
Get
Return _maxThreadCount
End Get
Set(ByVal value As Integer)
If value > Environment.ProcessorCount * 2 Then
_maxThreadCount = value
Else
value = Environment.ProcessorCount
End If
LogFacade.LogInfo(_logger, "Maximum Thread Count set to " & _maxThreadCount)
End Set
End Property
#End Region
End Class
You shouldn't SyncLock the instance or the type. You always want to SyncLock on a variable that is fully within the control of the class, and neither of those are. You should declare a private New Object and use that for your SyncLock.
Private lockObject as New Object()
...
SyncLock lockObject
...
End SyncLock
Unfortunately, you need to do a few things differently here.
First off, I'd recommend avoiding SyncLock, and using Interlocked.Increment and Interlocked.Decrement to handle changing _availableThreads. This will provide thread safety for that variable without a lock.
That being said, you still will need a SyncLock around every access to your Queue - if it's being used from multiple threads. An alternative, if you're using .NET 4, would be to change over to using the new ConcurrentQueue(Of T) class instead of Queue. If you use SyncLock, you should create a private object only accessible by your class, and use it for all synchronization.
You should be using the Interlocked class here, the Decrement() method to decrease the count. Yes, everywhere the variable is accessed.
Using SyncLock Me is as bad as SyncLock GetType(Me). You should always use a private object to lock on so nobody can accidentally cause a deadlock. The golden rule is that you cannot lock data, you can only block code from accessing data. Since the code is your private implementation detail, the object that holds the lock state must also be a private detail. Neither your object (Me) nor the Type of that object is private. Allowing other code to lock it by accident.
You can substitute the thread counter with Semaphore. If you use Semaphore you do not need to exit from while loop and neither it is necessary to call WorkThroughQueue() from ThreadCompleted event handler. Semaphore is thread safe so you can use it without locking.
http://www.albahari.com/threading/part2.aspx#_Semaphore