I'm just getting started with multi-threading. I am running a test of my multi-thread code but I'm getting an OutOfMemory exception.
The code is converting PS to PDF using a new thread. The task takes about half a second so for this test, I'm simply sleeping the main thread for a second to make sure I don't have too many tasks running. It did more than 900 before throwing an OutOfMemory exception.
I know I need to use Thread Pool, Semaphore or Task Parallel to limit my threads, but for now I'm just doing a test of my threads.
Dim sr As New StreamReader(PSTempFolder & "PDFWrite.txt")
Do While Not sr.EndOfStream
'get PS
Dim FileNamePS As String = sr.ReadLine
'get folder
Dim CustFolder As IO.DirectoryInfo
CustFolder = GetCustFolder(FileNamePS)
'set PDF path and name
FileNamePDF = CustFolder.FullName & "\Statement.pdf"
Dim t As Thread
Dim n As ConvertPDF = Nothing
n = New ConvertPDF
n.DeletePS = False
n.PSFileName = FileNamePS
n.PDFFileName = FileNamePDF
t = New Thread(AddressOf n.callConvertToPDF)
t.Start()
'wait
Thread.Sleep (1000)
Loop
sr.Close()
It seems it must be creating too many threads and not cleaning up the old ones. How do I clean up/dispose of the thread before creating a new one?
I suppose a second solution (in this context) would be simply using the same thread (I think I can do that), but for this question I'm more interested on disposing of the thread and releasing the memory. How do I do that?
Here is the rest of the code:
Class ConvertPDF
Public PSFileName As String
Public PDFFileName As String
Public DeletePS As Boolean = False
Delegate Function ConvertToPDFdel(ByVal svPsFileName As String, _
ByVal svPDFName As String, _
ByVal DeletePS As Boolean) As Integer
Sub callConvertToPDF()
Dim dlgt As New ConvertToPDFdel(AddressOf ConvertToPDF)
Dim i As Integer = dlgt.Invoke(PSFileName, PDFFileName, DeletePS)
End Sub
End Class
Public Function ConvertToPDF(ByVal svPsFileName As String, _
ByVal svPDFName As String, _
ByVal DeletePS As Boolean) As Integer
'check for file
If Not IO.File.Exists(svPsFileName) Then
Throw New ApplicationException(svPsFileName & " cannot be found")
End If
'delete old file
If IO.File.Exists(svPDFName) Then IO.File.Delete(svPDFName)
'convert
Dim myProcInfo As New ProcessStartInfo
myProcInfo.FileName = DanBSolutionsLocation & "Misc\GhostScript\GSWIN32C.EXE"
myProcInfo.Arguments = "-sDEVICE=pdfwrite -q -dSAFER -dNOPAUSE -sOUTPUTFILE=""" & svPDFName & """ -dBATCH """ & svPsFileName & """"
'Debug.Print(myProcInfo.Arguments)
'do the conversion
Dim myProc As Process = Process.Start(myProcInfo)
'wait for finish (no more than 20 seconds)
myProc.WaitForExit(20000)
myProcInfo = Nothing
myProc.Dispose()
'delete PS
If DeletePS Then
If IO.File.Exists(svPDFName) Then IO.File.Delete(svPsFileName)
End If
End Function
EDIT: I did some more testing between GroverBoy's code and mine and the results are inconclusive. Sometimes one is better sometimes the other. Maybe the two really are the same and the problem is elsewhere.
The new thread starts a new process that takes 0.55 seconds to complete. If the main thread waits 1 second each iteration, that should mean that we'll never have more than one thread or one open file at a time. Why isn't this true?
What actually happens will vary and I'm not sure why. I'm testing with a loop of 100 and a 1 second wait on the main thread. I usually watch the Performance tab of the Task Manager. Sometimes I run the code and number of threads will fluctuate between 2-6 extra and the Commit Charge will fluctuate between 1044M to 1150M. This is what I want.
Other times I run the same code (100 iterations) and the number of threads keeps rising to more than 63 extra. And the Commit Charge keeps rising from 1044M to more than 1272M.
What can I do to ensure that the program will clean up the threads consistently?