none
Threading Error - Skipping a LIne of Code RRS feed

  • Question

  • Okay,

    Now I could get "into it" with depth but I won't, because if I do, i will have countless people clamoring at me about "WHy are you doing that!"  Well, I don't care about what everyone thinks of my programming style, I want a fundamental question answered, not a critic session. 

    I've got two threads, the main thread and a worker thread.  (instantiated via Thread.Thread.Start())

    I've got a class which i create two instances of, one in the main thread and one in the worker thread, and they communicate with each other.  (don't ask, the communication is thread safe).  In this class, I check if something exists within its buffer, and if there is something there, I read it and pass it along via events, and once that data is processed I clear the buffer, so the next check against the buffer reveals the next command in the buffer or nothing. 
    Pseudo Code:
    do
    If CheckCommand() then
       ProcessCommand()
       CommandBuffer.Reset()
    end if
    loop until CommandBuffer.Terminated

    Simple concept.  Now when I write to the buffer, it uses the same buffer to write as it does to read, but since my communication is Half-Duplex by program sequence they should never overlap.  So WOrker thread writes a command into its buffer which is received by the Main Thread's Command Buffer and Processed.  Then the Main Thread COmmand Buffer writes back an OK message, meaning, the worker thread can send another command through.

    so currently this is the error:
             Strm.Write(Buffer, 0, 4 + If(Size > 0, 4 + Size, 0))
             Reset() '<- this line is not executing on the Worker Thread
             Return True

    And this is a Must-be-cannot-be-anything-else glitch.  Reason for confidence:

    think of the two threads as client server, where client is the worker thread.

    Client sends message to server and clears its buffer, and waits for response - Sent Code 1553
    Server Recieves message, processes and sends All Clear signal - Received 1553, sends 1024
    Client Receives all Clear and Sends next Message, waits for response - Receives 1024, Sends 1553
    Server Recieves next message and sends all clear - REceives 1553, sends 1024
    Client Receives all Clear and Sends next message, waits of Response - Receives 1024, Sends 1553
    Client Believes it has received a message, but the command code is the same as the code it just sent.   - Receives 1553

    What could be causing the Thread to jump that "Reset()" line which clears out the buffer? 

    Further Detail:
    Previously, the Server and Client were reversed, but since the Server needs to communicate with the Form, I cannot Invoke() a method to set controls (progress bars) because the Main Thread is active with the client.  So I reversed the "polarity" if you would, putting the server on the main thread so it could interact with the form.  This means that the client actions are occuring now in the worker thread, one aspect of which is using a WebClient asynchronously.

    Again this is some of that craptastic .Net design, as I MUST use WebClient.DownloadFileAsync() because if I just use DownloadFile() I get no progress reports.  So my setup was to simply fake out the system like this:

             _wc.DownloadFileAsync(url, unc.File.Name.AsFile(_updPath).FullName, UPD)
             Do Until _downloaded OrElse _canceled : Application.DoEvents() : Loop

    that block used to occur without incident in the main thread, while the server was on the worker thread.  I've reversed that now, so the below method handling the progress updates:
       Private Sub _wc_DownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs) Handles _wc.DownloadProgressChanged
          Dim upd As UpdateClient = DirectCast(e.UserState, UpdateClient)
          If Not _firstRun Then _canceled = Not upd.CheckOK() Else _firstRun = False
          If Not _canceled Then
             'Console.WriteLine("Client: " & e.BytesReceived)
             upd.UpdProgress.StatusMessage = upd.UpdProgress.StatusMessage.DeleteSplit(",", 2) & "," & e.ProgressPercentage
             upd.UpdateProgress(CType(e.BytesReceived, Integer))
          End If
       End Sub
    and as you see the upd.CheckOK() is looking for the response from the server that it received the last UpdateProgress() transmission.  the UpdateProgress() transmission, fills the command buffer, sends the command across the communication lines, and then clears the buffer, and the next iteration is reaching that CheckOK() and thinking the command is still 1553, instead of finishing the transmission of the UpdateProgress()  before it receives the next WebClient() update. 

    I recognize this is probably due to the a third thread, the thread that is asynchronously executing the webclient download, which means that the Event Method is being triggered before the last one finished...at least that is the only thing I can think is happening. 

    I'm guessing, that to retain thread safety, the webclient downloads the file and triggers a progress event, but triggers it on the WebClient's Calling thread, while letting the internal download thread continue downloading, in such a case it could end up triggering another event before the calling thread has finished execution of the previous event call. 
    Is there by chance any suggested method for delaying this habit, or controlling the flow of the "multiple" threads.
    Better yet, would be a Class that is similar to the WebClient() allowing me to download a file from either a Network UNC Share, Web Page, or FTP site, that will provide Progress events Syncrhonously (not Asynchronously)

    and yes, i did this test to verify something, putting in Enter and Exit text in the console at the beginning and ending of the DownloadProgress() event and this is what outputted:
    Entering DL Progress
    Client Sending: 1553
    Server: 1553
    SelfUpdateDownload
    Updating AutoUpdate System: Downloading...,UpdateInstall(1.2.3.11b).upd,11
    Desc: Updating AutoUpdate System: Downloading...
    Item: Downloading: UpdateInstall(1.2.3.11b).upd Progress: 65556{6334261} - 1%
    Exiting DL Progress
    Entering DL Progress
    Server Sending: 1024
    Entering DL Progress
    Client Sending: 1553
    Entering DL Progress
    Not OK: 1553
    Exiting DL Progress
    SO you see there are two concurrent "Entering DL Progress" is there any way that I can avoid/resolve this?

    Thanks
    Jaeden "Sifo Dyas" al'Raec Ruiner







    "Never Trust a computer. Your brain is smarter than any micro-chip."
    Friday, June 12, 2009 5:40 PM

Answers

  • Quite right.  The simplest explanation is the right, tragically everyone tends to responds the that simplest explanation is that .Net could never be the cause.  I rewrote WebClient using the WebRequest base class, so that I could be provided progress updates without having to utilize a .Net Async operation.  And guess what.  No Glitch.  No Error, Problem solved.  Why?  Because I re-wrote the webclient my way.

    Sometimes I think people should trust me when I say I know what the problem is and I just don't know how to solve it, or better said I don't know the best way to solve it.  My Communication system was not in err, as I pointed out with the text outputs from the WebClient.DownloadFileAsync() progress event handler.  Therefore, by re-writing the WebClient to be a syncrhonous operation instead of asynchronous,  the progress event is never fired before the last one finishes.  So yes, my communication system may or may not be "thread safe" semantically speaking, but the problem did exist in the .Net framework's handling of asynchronous operations, which I will compensate for in the future. 

    Thanks Anyway,
    Jaeden "Sifo Dyas" al'Raec Ruiner
    (I have never had to rewrite so much library code since I started using .Net)
    "Never Trust a computer. Your brain is smarter than any micro-chip."
    • Marked as answer by JaedenRuiner Monday, June 15, 2009 1:25 PM
    Monday, June 15, 2009 1:25 PM

All replies

  • don't ask, the communication is thread safe
    It's not.

    Hans Passant.
    Friday, June 12, 2009 6:59 PM
    Moderator
  • The simplest explanation is usually the right one, based on the trace it looks like the client sends a new command while the server is still not completely done processing the first one (including the Reset operation). On the server side unless sending of the OK (the ack for new message) and the Reset are coupled together as an atomic operation there is a chance to get a new command while Reset was not done yet : server sends OK, gets preempted, client sends, server gets new request.  Make sure Reset was called before the client gets the OK back and sends you a new message.

    Saturday, June 13, 2009 4:43 PM
  • Quite right.  The simplest explanation is the right, tragically everyone tends to responds the that simplest explanation is that .Net could never be the cause.  I rewrote WebClient using the WebRequest base class, so that I could be provided progress updates without having to utilize a .Net Async operation.  And guess what.  No Glitch.  No Error, Problem solved.  Why?  Because I re-wrote the webclient my way.

    Sometimes I think people should trust me when I say I know what the problem is and I just don't know how to solve it, or better said I don't know the best way to solve it.  My Communication system was not in err, as I pointed out with the text outputs from the WebClient.DownloadFileAsync() progress event handler.  Therefore, by re-writing the WebClient to be a syncrhonous operation instead of asynchronous,  the progress event is never fired before the last one finishes.  So yes, my communication system may or may not be "thread safe" semantically speaking, but the problem did exist in the .Net framework's handling of asynchronous operations, which I will compensate for in the future. 

    Thanks Anyway,
    Jaeden "Sifo Dyas" al'Raec Ruiner
    (I have never had to rewrite so much library code since I started using .Net)
    "Never Trust a computer. Your brain is smarter than any micro-chip."
    • Marked as answer by JaedenRuiner Monday, June 15, 2009 1:25 PM
    Monday, June 15, 2009 1:25 PM