I have a question regarding the synchronization in multi threading.
I have a function called send which i am calling in a for loop for every data row.
This function creates threads to send emails to different people.
Public Sub send(ByVal Conn As Data.DataRow, ByVal job As Data.DataRow)
MyThread = New Thread(AddressOf Me.start)
MyThread.Start()
End Sub
But every thread created is writing to a log file at different points of time. So, there are very high chances that 2 threads write to the same file at the same time. So, do i need to use any kind of synchronization mechanisms here ? or is it fine without them ? If yes, can any one please tell me what to use and where to use.
To prevent multiple threads from writing at the same time, use SyncLock. For example, myLogFile is your log file:
SyncLock myLogFile
myLogFile.WriteLine("message");
End SyncLock
Several approaches:
Your thread can obtain a lock on your logger object prior to calling the loggers log methods. This makes it the callers responsibility to lock.
Optionally you can move the locking responsibility into the logger object by having it manage the locking. See Jim's answer.
If you aren't wrapping your logging functionality into a separate object then simply create an object in your code that you can lock on.
Additionally, I wouldn't spawn a thread per record unless you know you will always have a small number of records. Otherwise you'll create context switch thrashing and hurt perf. Look into the Thread.QueueUserWorkItem() static method.
You will have an access error if one thread is blocking the file because it is writing to it. You can handle the exception, have the current thread wait and then write to the file.
boolean AttemptingToWrite = true
while (AttemptingToWrite)
try
WriteToLog()
AttemptinToWrite = false
catch(ex as exception
system.threading.thread.sleep(100)
end try
end while
Related
I have a BackgroundWorker routine that performs a lot of things and call ThreadSafe functions to update UI controls. In some points of that routine I call some subroutines to write log information into a SQL table, using the Parallel Library to make them in another Thread. It´s functioning like a charm.
The threaded LOG calls are like this, where Log_Compressed_File() is a subroutine:
Dim Log_Threaded as Thread = New Thread(Sub() Log_Compressed_File(Username, UserAreaCode, Filename))
Log_Threaded.IsBackground = False
Log_Threaded.Priority = ThreadPriority.Highest
Log_Threaded.SetApartmentState(Threading.ApartmentState.MTA)
Log_Threaded.Start
As shown above, each log call is made using 5 lines of code, defining the new thread itself and some important parameters.
My questions are:
1) can I produce a Sub to address these calls, trying to reduce the lines of the main routine?
Just to make it clear: I have more than 35 LOG calls within the main routine and, if each one would utilize 5 lines of code, I will have 175 lines, when I could have only the original 35 calls to a new subroutine that could address the new thread.
2) Can I call that subroutine from within the BackgroundWorker without to call a delegate function (ThreadSafe) like I use in UI updates?
The function like shown above can be performed within the BackgroundWorker without to a DELEGATE function (the LOG_COMPRESSED_FILE is a normal Sub, not a Delegate call).
Thanks in advance for any help!
Yes. Just write a method with the same three parameters as your Log_Compressed_File method and then put that code into that method.
Yes. Do you understand why you need to use a delegate at all? The point is that you cannot access the Handle of a control on any thread other than the one it was created on. Invoking a delegate ensures that code accessing the control's Handle is executed on the correct thread. If you're not accessing a control then there's no Handle so why would it matter what thread you execute the code on?
Second question on here...
Basically I am having a problem with a Stackoverflow exception that is thrown in my program, and I literally have no idea on how to locate the cause..
I have a program which has a plugin system, and it's a program that utilizes TCP in order to send and receive data; Server-> Client. I am making a remote console plugin, and the problem occurs when I do the command 'tree'; the filesystem entries listing command. For the first few seconds everything goes alright; the commands are being outputted (sent from Client to server). The receiving packets event isn't thread safe, so in the API I've provided an invocation function (to invoke methods on the UI thread). So therefore on output, it will do the following:
Public Sub ClientReadPacket(Sender As IClient, Pipename As String, Values As Object())
Select Case DirectCast(Values(1), ConsoleCommands)
Case ConsoleCommands.Output
ServerGUI.Send(Sub() ConsoleOutput.AppendText(Values(2) & Environment.NewLine))
End Select
End Sub
As you can see, the ServerGUI is an interface that I have provided for plugin development. And in the actual program - in the class that implements the GUI interface, I get a stackoverflow exception right here:
Private Sub ISend(del As System.Threading.SendOrPostCallback) Implements IGUI.Send
UIThread.Send(del, Nothing)
End Sub ' The break point is here; I assume that means that the exception ocurs in the line above.
The UIThread object is a synchronizationcontext of the main thread.
http://i.gyazo.com/870d9667f2272969b650cea836adca50.png
Update: So far I've narrowed it down to the following; it must be causing stackoverflow exception when calling SynchronizationContext.Send() too often, and the same happens when I rather use Invoke() in the plugin, it also gives a Stackoverflow exception.
I tried using asyncoperation, and this does not crash, but due to the fact that it's solely asynchronous is a problem, because my program becomes unresponsive when using Post(), because it continuously Posts (due to the fact that it will manage the next packet before the asyncoperation has posted.
I'm building a server and a client for a chat that runs on Tcp and Sockets, I want the client to handle more than one connection (to servers) so I made a class called "Client" to manage the async connection, so that I can run more instances at the same time like:
Dim ConnectionToServer1 as new Client
Dim ConnectionToServer2 as new Client
Since it's async when the the "connection" receives a message it generates an event (AsyncCallback) where I can convert the received bytes into a string.
The problem is: I've tried to set this string to a RichTextBox on my Form from inside the Client class, but nothing happens, I've tried to create a delegate in the form code but nothing works, the only way I was able to put the received message in the RichTextBox is by creating a public variable called LastMessage in the Client class where the last message is stored (every time it receives a message, the sub overrides the string), and then running a thread created by the Form which keeps checking for data (since the thread has been created by the form it has access to the controls, including the RichTextBox, right?)
Although I find this a bit clunky, is there any other way (through delegates maybe?) I can do it?
Here's some code:
Client class: http://pastebin.com/GF9um8Ss
Form code: http://pastebin.com/xW7mDj8j
Sounds like you started down all the right paths.
Now, on threaded applications one of the challenges that you will face is you can have tons of worker threads, but only the main, UI thread can actually make any updates to the UI. So keeping that in mind, if you have async code that needs to update the ui you will need to use what is effectively a delegate.
You can do this using tasks these days a lot easier, so read up on the Task Parallel Library, but essentially you need a delegate/task that is marshaled to run on the ui thread to handle the UI updates.
Set this global property as false
Control.CheckForIllegalCrossThreadCalls = false
this will let you edit any control of your form from any thread
I've been busy updating my brain with the TPL because I intend on using it for my new application (which uses .Net Framework 4.0). However I have some doubts that someone might clarify for me. Previously, I had a progress form which I would launch from the main (GUI) thread after I started the thread which needed to display its' progress. It looked something like this:
sortThread = New Thread(AddressOf _Sorter.Sort())
_ProgressForm = New FrmProgress()
_Sorter.ProgressForm = _ProgressForm
sortThread.Start()
progressForm.ShowDialog()
Basically it would initialize the thread, initialize a FrmProgress form object and assign it to the Sorter object which would then update the progress form (which contained a progress bar and some labels) from its Sort() sub on the separate thread. Updating these control properties was achieved by checking the InvokeRequired property of the FrmProgress form and if needed it would then use the Invoke() method of the control that was to be updated... ex:
Public Sub IncrementProgressBar(x As Integer)
If Me.InvokeRequired Then
pb_MainProgressBar.Invoke(Sub() IncrementProgressBar(x))
Else
pb_MainProgressBar.Increment(x)
End If
End Sub
Now I am interested in using TPL to launch separate worker threads (multiple) that may want to update the progress bar. Should I use the same pattern or should I consider accessing a public TaskScheduler.FromCurrentSynchronizationContext context that was obtained in the main GUI thread? In both cases I suppose I should provide some kind of locking mechanism on the form (SyncLock?)
Invoke should be sufficient, as you are doing. If two different threads try to invoke in parallel the first one will execute first, then the second when the UI thread becomes free. The UI thread cannot service two invokes simultaneously - they are naturally handled in FIFO sequence so there is no issue with thread safety. Any number of threads can invoke on the main thread without worrying about each other or using any additional locking mechanism.
Note, however, that any thread calling Invoke will block until the main thread can service the call. If you, for example, had many threads invoking heavy code at the same time then your various threads would block on the invoke calls until they got their kick at the can, so to speak. If you use BeginInvoke then the calling thread will simply continue executing and the invoked method will be placed in the UI thread's queue (which it will service as soon as it can).
I am using an external DLL (pdfsharp) to open (then manipulate) lots of PDF files. I use:
Dim inputDocument = Pdf.IO.PdfReader.Open(PDFPath, IO.PdfDocumentOpenMode.ReadOnly)
Problem is - it seems to hang on certain, rare files. I don't seem to get any timeout - it just hangs for hours on this line. We read thousands of files with this code, always on tiny files, so I was thinking that a quick workaround might be to somehow timeout if the this method takes more than a second or two. But I don't see a simple way to do this. I am hoping to avoid spinning up a worker thread.
Any thoughts on how I might limit this threads allowed execution time, or is there a better (but simple) way?
The Open() call should not hang. Never. If you provide us with a file that causes Open() to hang, we can investigate this.
Does your program run on a server? Do you use a DEBUG build of PDFsharp? Maybe it's just a simple Debug.Assert() that is triggered, but noone can answer it. Using a RELEASE build would solve this.
We ended up working around this problem by creating an AbortableBackgroundWorker. I am not sure whose code this ended up being - but we found it online and sharing it here. In the rare case where one of the PDF's hangs the PdfSharp Open() call, we abort the background worker.
Public Class AbortableBackgroundWorker
Inherits BackgroundWorker
Private workerThread As Thread
Protected Overrides Sub OnDoWork(e As DoWorkEventArgs)
workerThread = Thread.CurrentThread
Try
MyBase.OnDoWork(e)
Catch generatedExceptionName As ThreadAbortException
e.Cancel = True
'We must set Cancel property to true!
'Prevents ThreadAbortException propagation
Thread.ResetAbort()
End Try
End Sub
Public Sub Abort()
If workerThread IsNot Nothing Then
workerThread.Abort()
workerThread = Nothing
End If
End Sub
End Class