rheitzman rheitzman - 2 months ago 18
Vb.net Question

Filestream read only locking PC

I'm trying to read the Windows update log on remote PCs on my LAN. Most of the time I can successfully read the file but at times the program locks up. Likely due to one issue or another - doesn't really matter. What I do need is a way to recover when the Filestream/Streamreader locks up - I'm not sure which is causing the lock. Some streams can set a timeout but the filestream below returns False on a .CanTimeout call.

How can I break out if the stream locks up? (Sometimes the lock is so tight a power off is needed to recover.)

Is there a way to test if the stream will fail before I actually attempt the read?

Is there an alternate way to read a remote log file that another program has open? (I'm using the stream method because the regular File.IO was blocked because the file is open on the remote PC.)




I'm getting closer (I think) with this code. I browed the pathExists code from the referenced post but it was the OP and not an answer.

Imports System.IO
Import System.Threading
...
Function GetAULog(PCName As String) As String
Try
Dim sLogPath As String = String.Format("\\{0}\c$\Windows\SoftwareDistribution\ReportingEvents.log", PCName)
If PCName = My.Computer.Name Then
sLogPath = String.Format("C:\Windows\SoftwareDistribution\ReportingEvents.log", PCName)
End If
' read file open by another process
If Not pathExists(sLogPath) Then
MsgBox("AU log file not found - PC on?")
Return "NA"
End If
Using fs As New FileStream(sLogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
Using sr As New StreamReader(fs)
Dim s As String = sr.ReadToEnd
Return s
End Using
End Using
Catch ex As Exception
MsgBox(ex.Message)
Return ""
End Try
End Function

Public Function pathExists(path As String) As Boolean
Dim exists As Boolean = True
Dim t As New Thread(New ThreadStart(Sub() exists = System.IO.File.Exists(path)))
t.Start()
Dim completed As Boolean = t.Join(500)
'half a sec of timeout
If Not completed Then
exists = False
t.Abort()
End If
t = Nothing
Return exists
End Function


At least when the PC is off the pathExists() code returns False in short order.

My problem now is the process does not end when the program exits - at least in the IDE, didn't check runtime.

I added
t = Nothing
but that didn't help. I couldn't figure out the proper Using syntax to test that. How do I properly cleanup after a thread timeout?

Answer

"Final" code shown below. The exceptions are not firing when the timeout occurs so the .Abort was evidently OK.

When the timeout does occur, because the remote PC did not respond, there is a process left hanging which goes away after 30 seconds or so. I notice this when using the IDE, I run the program and test a PC that is off. If I then exit the program the form closes but the IDE hangs for ~30 seconds - I can click Stop-Debugging at this point and it works, but the IDE continues on its own after the ~30 second timeout.

I guess the t = Nothing in the Finally block does not dispose of the thread. t.Dispose does not exists.

So, things are working OK with the exception of the dangling thread that eventually clears itself up. The program is no longer hanging to the point where it cannot not be stopped.

'Imports System.IO
'Imports System.Threading
Public Function pathExists(path As String) As Boolean
    ' check for file exists on remote PC
    Dim exists As Boolean = False
    Dim t As New Thread(New ThreadStart(Sub() exists = System.IO.File.Exists(path)))
    Try
        t.Start()
        Dim completed As Boolean = t.Join(500)
        'half a sec of timeout
        If Not completed Then
            exists = False
            t.Abort()
        End If
    Catch ex2 As ThreadInterruptedException
        MsgBox("timeout on AU log exists test" & vbNewLine & ex2.Message,, "ThreadInterruptedException")
    Catch exAbort As ThreadAbortException
        MsgBox("timeout on AU log exists test" & vbNewLine & exAbort.Message,, "ThreadAbortException")
    Catch ex As Exception
        MsgBox("exception on AU log exists test" & vbNewLine & ex.Message)
    Finally
        t = Nothing
    End Try
    Return exists
End Function