PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197

PHP User Warning: fetch_template() calls should be replaced by the vB_Template class. Template name: bbcode_highlight in ..../includes/functions.php on line 4197
VS 2013 Issues using BGW for graphing-VBForums
Results 1 to 33 of 33

Thread: Issues using BGW for graphing

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Issues using BGW for graphing

    So I'm converting VB6 code that is littered with Do Loops, some doing nothing but waiting various amounts of time for hardware to stabilize and some reading an analog channel until a certain value is met. In general, UI responsiveness is not important for most of these (nothing the operator can do while test is running) so can I just use Thread.Sleep and be done with it? Even though it will freeze the UI, it seems so much simpler than trying to split all the following code into a timer, checking for state variables, etc.

    I originally posted this question on JMC's Pause thread but moved it here. I may try to split off the main one that has the DoEvents call into another thread so the real-time graph will display better though my tests indicate that should be fine as is (though it will run the CPU more than needed, of course). The VB6 code was using a progress bar rather than graph.

    The VB6 code pegged the CPU at 100% for most of the test as one would expect. The .Net code will run on much newer hardware (dual core even - LOL).
    Last edited by topshot; Feb 6th, 2015 at 06:05 PM. Reason: Changed title to reflect thread drift

  2. #2
    Bad man! ident's Avatar
    Join Date
    Mar 2009
    Location
    Cambridge
    Posts
    5,326

    Re: Sleep vs timers for asynch hardware?

    The reason you dont get a reply is as the sub section is title CODE BANK. It's not a place to ask questions. So please explain here with a full and descriptive response what you are trying to do.

  3. #3
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    34,326

    Re: Sleep vs timers for asynch hardware?

    Yeah, CodeBank threads are rarely visited by the original authors.

    It sounds like you could get away with Thread.Sleep, but I'd still advise against it. A sleeping UI is an odd thing, even if it makes sense that the user can't do anything with the UI during that time. It just seems so frozen, and we have trained people that a frozen UI is a sign of terminal illness (which is kind of odd, since we really trained them in the era of PCs, after terminals had been abandoned).

    Better yet would be to do ALL of that waiting around stuff on background threads which you can go ahead and freeze for as long as feels good to you. While that is running, you can toss something up on the UI thread that lets the user feel all warm and happy about the application, even while it really isn't doing anything. What I have done in the past is to put up a message in a form. The background of the message cycles through colors using an algorithm that I think will cause it to cycle through ALL the colors that can be displayed on the screen in a chaotic cycle that won't repeat exactly for a very long time...but I digress. The point is to show the user SOME kind of action, even if it is meaningless.
    My usual boring signature: Nothing

  4. #4

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    Here is my post from JMC's Pause thread, which I'll remove and point to here instead. There is a message on the screen that informs them what stage of the test is currently running.


    Dumb question perhaps, but what would be the best way to implement this when you have code (converting from VB6) that has several Do Loops within a routine to pause for hardware or a value to stabilize? It would seem breaking it up into many different routines would be a major pain to keep track of.

    This routine (greatly simplified) is doing one test on a product. These busy wait loops litter the code in other similar routines. I should also note that UI responsiveness is not all that critical (other than drawing a graph or updating some labels) here since once the operator starts the test there's nothing they can do until it finishes.

    vb Code:
    1. If SomeCondition Then
    2.             SetSpeed(100)
    3.  
    4.             StartTimer = Date.Now.TimeOfDay.TotalSeconds
    5.             Do
    6.                 temp = Date.Now.TimeOfDay.TotalSeconds - StartTimer
    7.                 If temp < 0 Then temp = temp + 86400
    8.                 Checkspeed(RealSpeed)
    9.             Loop Until RealSpeed < 600 OrElse temp > 10
    10.         Else
    11.             StartTimer = Date.Now.TimeOfDay.TotalSeconds
    12.             Do
    13.                 temp = Date.Now.TimeOfDay.TotalSeconds - StartTimer
    14.                 If temp < 0 Then temp = temp + 86400
    15.             Loop Until temp > 0.5
    16.  
    17.         End If
    18.  
    19.         If SomeCondition Then
    20.             SetBit
    21.             StartTimer = Date.Now.TimeOfDay.TotalSeconds
    22.             Do
    23.                 temp = Date.Now.TimeOfDay.TotalSeconds - StartTimer
    24.                 If temp < 0 Then temp = temp + 86400
    25.             Loop Until temp > 1
    26.  
    27.             SetPressure = 4095
    28.         Else
    29.             SetPressure = 100
    30.         End If
    31.  
    32.         StartTimer = Date.Now.TimeOfDay.TotalSeconds
    33.         Do
    34.             temp = Date.Now.TimeOfDay.TotalSeconds - StartTimer
    35.             If temp < 0 Then temp = temp + 86400
    36.         Loop Until temp > 0.5
    37.  
    38.         StartTimer = Date.Now.TimeOfDay.TotalSeconds
    39.         Penetration = 0
    40.         i = -1
    41.         Do  'Ramp Speed from 600 to Max RPM
    42.             Penetration = elapsed(StartTimer) / RampTime
    43.             If Penetration > 1.1 Then Penetration = 1.1
    44.  
    45.             System.Windows.Forms.Application.DoEvents() 'GACK!
    46.  
    47.             SpeedOut = SpeedCounts * Penetration
    48.             SetSpeed(SpeedOut)
    49.             Checkspeed(RealSpeed)
    50.  
    51.             i = i + 1
    52.             If i > 0 And i Mod 100 = 0 Then 'graph every 100th point
    53.                 '******* Speed vs Flow **** Subset 0 ************************
    54.                 LiveGraph.Series("Series0").Points.AddXY(Data(3, i), Data(4, i))
    55.  
    56.                 '******* Speed vs Torque **** Subset 3 **********************
    57.                 LiveGraph.Series("Series3").Points.AddXY(Data(3, i), Data(2, i))
    58.             End If
    59.  
    60.         Loop Until Penetration >= 1 Or RealSpeed > MaxSpeed

  5. #5

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    I'll also note that being relatively new to threading that I'm hesitant to move too much stuff into BGWs so I don't "break" anything inadvertently. I know the old code worked (at the expense of CPU usage) and we'll be going live with no chance for me to test in advance (aside from the few days we've set aside for debug). I'm already hoping the serial port threading will work like it should. I hadn't expected that little surprise. I'm now wondering what else is threaded by default that didn't used to be but I digress.

  6. #6
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Sleep vs timers for asynch hardware?

    Throw it in a background worker, get rid of the do events, and flag the progress to the UI for the chart update.

    Instead of the loops, you can either keep them and add small sleeps, or if its just waiting, then replace it with a sleep.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  7. #7
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    34,326

    Re: Sleep vs timers for asynch hardware?

    So, it's not just BGW you are hesitant about, it's threading solutions in general. I can understand that if you don't get to test changes. ANY change can break things, and moving to a threaded solution can certainly break things due to the amount of rewriting potentially required, but that's the whole issue. If you can't break anything, then you can't really rewrite anything, either, which means you've lost all the value of the upgrade. Most of VB6 code will run in .NET just fine, though some data types should be altered for efficiency. Why would you bother with changing languages if you don't have the freedom to actually change the code to take advantage of modern options?

    There is plenty that can be done to that, but not without rewriting it to make use of either threading or asynchronous operations, both of which look quite promising for that solution. Any such change would require that the code be tested again, though, which it doesn't sound like you can do.
    My usual boring signature: Nothing

  8. #8

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    Quote Originally Posted by Shaggy Hiker View Post
    Why would you bother with changing languages if you don't have the freedom to actually change the code to take advantage of modern options?

    There is plenty that can be done to that, but not without rewriting it to make use of either threading or asynchronous operations, both of which look quite promising for that solution. Any such change would require that the code be tested again, though, which it doesn't sound like you can do.
    I had told them they wouldn't really gain anything going to .Net for this app but that is what they wanted. They think the code is part of the issue of poor tester performance when it's really manufacturing and supplier issues, but alas.

    Anyway, if I can do as SJWhiteley suggests and throw the whole routine into a BGW then maybe it won't be such a mess (in my eyes). I had thought about doing that for just the main Do Loop that contained the DoEvents. Am I correct in thinking that the code will continue on once I fire off the BGW (that's the whole point for them normally right? ) so I'll need to check a state variable to make sure the program does NOT continue with further tests until the BGW completes?

    So that begs a question: how do you start back up from where you fired off the BGW? Will I need to break the processing of the collected data (not shown in my above example) into a separate routine and call that new routine when RunWorkerCompleted fires. Then once that data processing routine completes, I can set the state variable and continue with the next test if it had passed.

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    34,326

    Re: Sleep vs timers for asynch hardware?

    The nice thing about the BGW is that it raises some events on the UI thread. There are two events that would be of interest to you. The first is the ReportProgress event. That is for exactly what it sounds like, but it gives you a means to raise an event in the BGW that will be handled on the UI thread, so you can use it for updating displays and the like. The other event...I forget the name of it, but it's raised automatically on the UI thread at the termination of the BGW process. That's the one you would need to handle to start back up with your normal activity once the BGW has completed its work.

    It's unfortunate that those making the decisions don't understand the decisions they are making. The code would really benefit from threading or asychronous operation, but that's a bigger commitment, and it sounds like it wouldn't even address the bottleneck of the process, which sounds like it is more in the meatbag area than in the silicon area. You might try to make it clear to them that what they will get at first is not much, but that a better process would require more time and more testing, because it would be redesigning to make better use of modern CPUs (or whatever terminology would get through to them). They have options, and those options have cost, and they should be aware of them. Beyond that, as long as it isn't your decision to make, you've done your job.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    Quote Originally Posted by Shaggy Hiker View Post
    The nice thing about the BGW is that it raises some events on the UI thread. There are two events that would be of interest to you. The first is the ReportProgress event. That is for exactly what it sounds like, but it gives you a means to raise an event in the BGW that will be handled on the UI thread, so you can use it for updating displays and the like. The other event...I forget the name of it, but it's raised automatically on the UI thread at the termination of the BGW process. That's the one you would need to handle to start back up with your normal activity once the BGW has completed its work.
    I was just testing those in fact with some very puzzling (to me) results. I had expected the BGW to be faster but it's not. What is more puzzling to me though is that if I moved the form around the screen (checking for freezing) when using the BGW, it would screw up Chart1, missing a bunch of points when I first started moving the form, but not when I ran it without the BGW as shown below (it would freeze while moving but continue where it left off). Right now I'm just reading from a "dummy" AD card that's producing a sine wave. The original DoWork routine I had and the one for the BGW are identical other than having to move the loop into the latter as well as moving the Chart1 updating to the ProgressChanged event of course. So in the original case the message queue seems to have stalled while the form was being moved and then picking up where it was while the BGW just skipped over some of the ProgressChanged events that occurred at the start of form movement (or they were prevented from occurring at all). Why is that???

    vb.net Code:
    1. 'BackgroundWorker1.RunWorkerAsync()
    2.  
    3.         i = 65
    4.         Do
    5.  
    6.             Call DoWork(Analog1) 'read analog input
    7.  
    8.             i = i + 0.2
    9.             Chart1.Series("Series0").Points.AddXY(i, Analog1)
    10.  
    11.             Application.DoEvents()
    12.  
    13.         Loop Until (i > 200)

    Here is what I mean when using the BGW. Ignore the dark blue lines.
    Name:  BGW_Graph.jpg
Views: 209
Size:  31.9 KB
    Last edited by topshot; Feb 6th, 2015 at 03:14 PM. Reason: Added picture

  11. #11
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Sleep vs timers for asynch hardware?

    Okay, you are seeing the issue in BGW but not when in the form code...okay, here's the thing: the 'form' code, running on the UI thread appears correct because you are running a simulation. The BGW is actually much closer to reality.

    In the Form, you are generating points. Move the form and the points stop being generated, and chart stops updating. Allow the form to continue, and points are generated where they left off, and charting continues where it left off - it appears correct.

    In the BGW, you are generating points. Move the form, the points continue to be generated, but the form cannot process the points for some reason: the form will continue to accept events. This is actually much closer to reality.

    Are you using ReportProgress to add the points to the chart? this event should be raised and consumed by the form. How are points added to the chart, and how is the chart drawn? I suspect this is an artifact of the drawing mechanism, and not the background worker.

    Add a debug statement to the ReportProgress and you should see the event raised repeatedly.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  12. #12

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    Quote Originally Posted by SJWhiteley View Post
    Are you using ReportProgress to add the points to the chart? this event should be raised and consumed by the form. How are points added to the chart, and how is the chart drawn? I suspect this is an artifact of the drawing mechanism, and not the background worker.

    Add a debug statement to the ReportProgress and you should see the event raised repeatedly.
    Indeed the ProgressChanged event is not firing for a short while. This is my DoWork routine:

    vb.net Code:
    1. i = 65
    2.         Do
    3.             elapsed.Start()
    4.  
    5.             ULStat = DaqBoard.AInScan(0, 6, 7, 2000, MccDaq.Range.Uni10Volts, MemHandle1, MccDaq.ScanOptions.Default)
    6.             ULStat = MccDaq.MccService.WinBufToArray(MemHandle1, ADData, 0, 7)
    7.             ULStat = DaqBoard.ToEngUnits(MccDaq.Range.Uni10Volts, ADData(0), EngUnits)
    8.             i = i + 0.2
    9.             GraphData(0, 0) = i
    10.             GraphData(1, 0) = EngUnits
    11.             worker.ReportProgress(0, GraphData)
    12.  
    13.             elapsed.Stop()
    14.             elapsedTime = elapsed.ElapsedMilliseconds
    15.             elapsed.Reset()
    16.             Console.WriteLine(CStr(i) & ":" & CStr(elapsedTime))
    17.  
    18.         Loop Until i > 200


    This is how the Chart get updated:
    vb.net Code:
    1. Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    2.         Dim GraphData(,) As Single = CType(e.UserState, Single(,))
    3.  
    4.         Chart1.Series("Series0").Points.AddXY(GraphData(0, 0), GraphData(1, 0))
    5.         Console.WriteLine("Added point at: " & CStr(GraphData(0, 0)))
    6.  
    7.     End Sub

    I'm seeing all the elapsedTime messages but when the form starts moving the elapsedTime is 0 instead of 10-18ms and I see no Added point messages from the ProgressChanged event. Shortly after the form starts moving everything goes back to normal though all the Added point messages to start have the same point number (repeated for how many it had missed it seems). Here is a snippet of the output that shows what I'm saying:

    Code:
    153.5986:16
    Added point at: 153.5986
    153.7986:21
    Added point at: 153.7986
    153.9986:13
    Added point at: 153.9986
    154.1986:0
    Added point at: 154.1986
    154.3986:13
    Added point at: 154.3986
    154.5986:13
    Added point at: 154.5986
    154.7986:13
    Added point at: 154.7986
    154.9986:13
    Added point at: 154.9986
    155.1986:13
    Added point at: 155.1986
    155.3986:13
    Added point at: 155.3986
    155.5986:12
    Added point at: 155.5986
    155.7986:12
    Added point at: 155.7986
    155.9986:12
    Added point at: 155.9986
    156.1986:12
    Added point at: 156.1986
    156.3986:13
    Added point at: 156.3986
    156.5986:14
    Added point at: 156.5986
    156.7986:13
    156.9986:0
    157.1986:0
    157.3986:0
    157.5986:0
    157.7986:0
    157.9986:0
    158.1986:0
    158.3986:0
    158.5986:0
    158.7986:0
    158.9986:0
    159.1986:0
    159.3986:0
    159.5986:0
    159.7986:0
    159.9986:0
    160.1985:0
    160.3985:0
    160.5985:0
    160.7985:0
    160.9985:0
    161.1985:0
    161.3985:0
    161.5985:0
    161.7985:0
    161.9985:0
    162.1985:0
    162.3985:0
    162.5985:0
    162.7985:0
    162.9985:0
    163.1985:0
    163.3985:0
    163.5985:0
    163.7985:0
    163.9985:0
    164.1985:0
    164.3985:0
    164.5985:0
    164.7985:0
    164.9985:0
    165.1985:0
    165.3985:0
    165.5985:0
    165.7985:0
    165.9985:0
    166.1985:0
    166.3985:0
    166.5984:0
    166.7984:0
    166.9984:0
    167.1984:0
    167.3984:0
    167.5984:0
    167.7984:0
    167.9984:0
    168.1984:0
    168.3984:0
    168.5984:0
    168.7984:0
    168.9984:0
    169.1984:0
    169.3984:0
    169.5984:0
    169.7984:0
    169.9984:0
    170.1984:0
    170.3984:0
    170.5984:0
    170.7984:0
    170.9984:0
    171.1984:0
    171.3984:0
    171.5984:0
    171.7984:0
    171.9984:0
    172.1984:0
    172.3984:0
    172.5984:0
    172.7984:0
    172.9984:0
    173.1983:0
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    Added point at: 173.1983
    173.3983:401
    Added point at: 173.3983
    173.5983:0
    Added point at: 173.5983
    173.7983:0
    Added point at: 173.7983
    173.9983:0
    Added point at: 173.9983
    174.1983:0
    Added point at: 174.1983
    174.3983:0
    Added point at: 174.3983
    174.5983:0
    Added point at: 174.5983
    174.7983:0
    Added point at: 174.7983
    174.9983:22
    Added point at: 174.9983

  13. #13

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    It is helped quite a bit but not totally if I add Thread.Sleep of at least 10 either before or after the ReportProgress call. That slows down the graphing, of course.

  14. #14
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,623

    Re: Sleep vs timers for asynch hardware?

    If you're still clicking on the titlebar to see the error, I've had issues with that as well.
    If you click on the titlebar and don't move the mouse, it seems some events like timer and paint, (and evidently, possibly reportProgress based on your experience) are suspended for up to 400ms, my assumption being that Windows is waiting to see if you are going to doubleclick the titlebar so it will either expand to full size, or return to normal size.
    Once that delay is done, or you start moving the window, the other events seem like they will start being processed again.
    The other thing I've noted, is that if you start dragging the window fairly quickly, if windows didn't refresh the desktop windows affected (and display your window in the new location if you have show window dragging enabled) things would look ugly, so processing mouse and doing screen updates take priority, so the mousemove events are processed rapidly while other GUI event processing is starved out until the mouse movement slows down enough so other events can slip into being processed.

    When I have a high priority background task that needs to process data regularly, and a GUI control that needs to reflect data from the background task, I don't use an event Raising scheme, but rather setup a ConcurrentQueue that the background task can send data to (Enqueue), and a timer (I usually name GUItimer and run at 10hz), will check for entries in the ConcurrentQueue (TryDequeue), and process all that it dequeues.
    You may need to do something like that.
    I haven't used a Background Worker much, as most of my background work runs for the duration of the application so I just use a background thread.

  15. #15

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    Quote Originally Posted by passel View Post
    If you're still clicking on the titlebar to see the error, I've had issues with that as well.
    If you click on the titlebar and don't move the mouse, it seems some events like timer and paint, (and evidently, possibly reportProgress based on your experience) are suspended for up to 400ms, my assumption being that Windows is waiting to see if you are going to doubleclick the titlebar so it will either expand to full size, or return to normal size.
    Once that delay is done, or you start moving the window, the other events seem like they will start being processed again.
    The other thing I've noted, is that if you start dragging the window fairly quickly, if windows didn't refresh the desktop windows affected (and display your window in the new location if you have show window dragging enabled) things would look ugly, so processing mouse and doing screen updates take priority, so the mousemove events are processed rapidly while other GUI event processing is starved out until the mouse movement slows down enough so other events can slip into being processed.

    When I have a high priority background task that needs to process data regularly, and a GUI control that needs to reflect data from the background task, I don't use an event Raising scheme, but rather setup a ConcurrentQueue that the background task can send data to (Enqueue), and a timer (I usually name GUItimer and run at 10hz), will check for entries in the ConcurrentQueue (TryDequeue), and process all that it dequeues.
    You may need to do something like that.
    I believe you are correct with the 400ms wait period. That's good to know. I would think I'd be OK since the operator would not be using the UI and the form is always maximized, however, I have simplified my test down as much as possible now and maybe it's just moving too fast since even if I don't do anything with the UI it's still missing some ReportProgress events (and doubling others) even if I use Sleep(30) which slows the graphing a lot.

    Other than designer code, here is the full code I'm using to test now:

    vb.net Code:
    1. Option Strict Off
    2. Option Explicit On
    3.  
    4. Imports System.Windows.Forms.DataVisualization.Charting
    5.  
    6.  
    7. Public Class frmDataDisplay
    8.  
    9.     Inherits System.Windows.Forms.Form
    10.  
    11.     Dim elapsed As New Stopwatch
    12.     Dim elapsedTime As Long = 0
    13.  
    14.     Friend WithEvents BackgroundWorker1 As System.ComponentModel.BackgroundWorker
    15.     Friend WithEvents Chart1 As System.Windows.Forms.DataVisualization.Charting.Chart
    16.  
    17.  
    18.     Private Sub cmdStartConvert_Click(ByVal eventSender As System.Object, _
    19.     ByVal eventArgs As System.EventArgs) Handles cmdStartConvert.Click
    20.         Dim i As Single
    21.         Dim ser As Series
    22.  
    23.         cmdStopConvert.Enabled = False
    24.  
    25.         For Each ser In Chart1.Series
    26.             ser.Points.Clear()
    27.         Next
    28.         Chart1.Titles("Title1").Text = "600 RPM Parking Curve"
    29.         Chart1.ChartAreas("ChartArea1").AxisX.Title = "BAR"
    30.         Chart1.ChartAreas("ChartArea1").AxisY.Title = "LPM"
    31.         Chart1.ChartAreas("ChartArea1").AxisY2.Title = "N*m"
    32.         Chart1.ChartAreas("ChartArea1").AxisX.Interval = 10
    33.  
    34.         Chart1.Series("Series1").Points.AddXY(69, 15)
    35.         Chart1.Series("Series1").Points.AddXY(175, 13)
    36.         Chart1.Series("Series1").Points.AddXY(195, 13)
    37.         Chart1.Series("Series1").Points.AddXY(195, 1)
    38.  
    39.         Chart1.Series("Series2").Points.AddXY(69, 10.8)
    40.         Chart1.Series("Series2").Points.AddXY(175, 8)
    41.         Chart1.Series("Series2").Points.AddXY(175, -0.1)
    42.         Chart1.Series("Series2").Points.AddXY(200, -0.1)
    43.  
    44.         Chart1.Series("Series4").Points.AddXY(69, 45)
    45.         Chart1.Series("Series4").Points.AddXY(200, 94)
    46.  
    47.         Chart1.Series("Series5").Points.AddXY(69, 16)
    48.         Chart1.Series("Series5").Points.AddXY(200, 56)
    49.  
    50.         'comment out this line if using the loop below
    51.         BackgroundWorker1.RunWorkerAsync()
    52.  
    53.         'comment out the following loop if running the BGW above
    54.         'i = 65
    55.         'Do
    56.         '    elapsed.Start()
    57.  
    58.         '    i = i + 0.2
    59.         '    Chart1.Series("Series0").Points.AddXY(i, MakeSineWave(i))
    60.  
    61.         '    Application.DoEvents()
    62.         '    elapsed.Stop()
    63.         '    elapsedTime = elapsed.ElapsedMilliseconds
    64.         '    elapsed.Reset()
    65.         '    Console.WriteLine(CStr(i) & ":" & CStr(elapsedTime))
    66.         'Loop Until (i > 200)
    67.  
    68.         cmdStopConvert.Enabled = True
    69.  
    70.     End Sub
    71.  
    72.  
    73.     Private Sub cmdStopConvert_Click(ByVal eventSender As System.Object, _
    74.     ByVal eventArgs As System.EventArgs) Handles cmdStopConvert.Click
    75.  
    76.         Application.Exit()
    77.  
    78.     End Sub
    79.  
    80.  
    81.  
    82.     Function MakeSineWave(radians As Single) As Single
    83.  
    84.         Return 3 * Math.Sin(radians) + 6
    85.  
    86.     End Function
    87.  
    88.     Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    89.         Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
    90.         Dim i As Single
    91.         Dim GraphData(1, 1) As Single
    92.  
    93.         i = 65
    94.         Do
    95.             elapsed.Start()
    96.  
    97.             i = i + 0.2
    98.             GraphData(0, 0) = i
    99.             GraphData(1, 0) = MakeSineWave(i)
    100.             Threading.Thread.Sleep(30)
    101.             worker.ReportProgress(0, GraphData)
    102.             'Application.DoEvents()
    103.             'Threading.Thread.Sleep(20)
    104.             elapsed.Stop()
    105.             elapsedTime = elapsed.ElapsedMilliseconds
    106.             elapsed.Reset()
    107.             Console.WriteLine(CStr(i) & ":" & CStr(elapsedTime))
    108.  
    109.         Loop Until i > 200
    110.  
    111.     End Sub
    112.  
    113.     Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    114.         Dim GraphData(,) As Single = CType(e.UserState, Single(,))
    115.  
    116.         Console.WriteLine("Added point at: " & CStr(GraphData(0, 0)))
    117.         Chart1.Series("Series0").Points.AddXY(GraphData(0, 0), GraphData(1, 0))
    118.  
    119.     End Sub
    120.  
    121.     Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    122.  
    123.         MessageBox.Show("Now you can process the data")
    124.  
    125.     End Sub
    126. End Class

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,623

    Re: Sleep vs timers for asynch hardware?

    Quote Originally Posted by topshot View Post
    ... I have simplified my test down as much as possible now and maybe it's just moving too fast since even if I don't do anything with the UI it's still missing some ReportProgress events (and doubling others) even if I use Sleep(30) which slows the graphing a lot...
    Yes, which is why I try to never interact directly with the GUI thread from a background thread. The GUI thread's message loop is at the mercy of the whims of Windows to do the things it needs to do to drive the display. It is a user interface, and the user can't react all that quickly to events so short delays, and other irregularities in the processing time of what a person sees is considered acceptable.

    I think you are also seeing another side effect which I've seen before, and that is that the method of queuing up the ReportProgress calls doesn't work the way you think it would.
    You would think that since you change GraphData each time before you do the ReportProgress, that on the other end when the Event is raised, you would have the data passed with the given call, but what appears to be happening is that method is asynchronous and will actually execute later when it can. When it can execute, it is called and passed the value in GraphData, which because of the delay in the actual call, is no longer the value it was when you made the call.
    So, if you did the ReportProgress five times over the period of a second, and it was held up, then at one second, suddenly all five calls can be done in 20ms, all five calls will pass the value of GraphData at the time they execute, so all five events on the GUI side, will contain the same GraphData values at that time they execute, not the time you called them.

    Essentially, your call really just put the call as a delegate on a queue, and that delegate will run at some later time at which time the data the delegate will copy to be sent as a parameter may have changed.
    I could be wrong, but I'm pretty sure I've seen that behavior. I would have to test it again. Rather than pass data as a parameter to an asynchronous delegate I would either use the concurrent Queue as already mentioned, although there can be possible short delays impacts depending on how the locking is done. I haven't had an issue that I've detected yet.

    Another, older approach I've taken, which doesn't have the overhead of the locking of an object by two threads, is use a simple array of structures as a ring buffer with two variables acting like a head and tail pointer. The one thread would only update the head pointer, and the other the tail pointer, so there is not a conflict there. And the two threads would never try to read the same element in the array at the same time, so no partial updated reads to worry about there either. Assuming the buffer is large enough to cover any delays on the GUI side, the GUI side should be able to catch up and drain items from the ring buffer, staying ahead of the thread filling the buffer. The side filling (assume it is incrementing the head pointer), should of course be reading the tail pointer to make sure it doesn't catch it, otherwise you have a buffer overflow. If you see that case, then increase the size of the buffer. Of course, if the ring buffer fills, the filling thread could have a List(Of T) FIFO list handy to add overflow things to which can build dynamically, and the filling thread check that first, and if there are items in the list, add its new value to that list, and then try draining as many from the overflow list into the ring buffer, assuming the overflow is just a temporary situation and that the GUI thread will catch up (unless you have it stopped because you're debugging ). In the debug situation, you could have a max count, and just stop adding things to the list, until the ring buffer starts being drained again.
    Last edited by passel; Feb 6th, 2015 at 07:33 PM.

  17. #17

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Sleep vs timers for asynch hardware?

    Quote Originally Posted by passel View Post
    I think you are also seeing another side effect which I've seen before, and that is that the method of queuing up the ReportProgress calls doesn't work the way you think it would.
    You would think that since you change GraphData each time before you do the ReportProgress, that on the other end when the Event is raised, you would have the data passed with the given call, but what appears to be happening is that method is asynchronous and will actually execute later when it can. When it can execute, it is called and passed the value in GraphData, which because of the delay in the actual call, is no longer the value it was when you made the call.
    So, if you did the ReportProgress five times over the period of a second, and it was held up, then at one second, suddenly all five calls can be done in 20ms, all five calls will pass the value of GraphData at the time they execute, so all five events on the GUI side, will contain the same GraphData values at that time they execute, not the time you called them.
    I think you may be correct again from what I've seen. It still happens even if I comment out the Chart update (eg, simply write the value to the console) in the ProgressChanged event.

    Rather than pass data as a parameter to an asynchronous delegate I would either use the concurrent Queue as already mentioned, although there can be possible short delays impacts depending on how the locking is done. I haven't had an issue that I've detected yet.
    To make sure I'm understanding what you're saying, you throw the values into a global array or list (queue) and then use a timer at 100ms to process and remove a value (or all current values?) from the array at each tick event. I'd assume all current values since you'd fall behind pretty fast otherwise.

    So in this case you need to lock the array when you add to it and when you take away so it would work very similar to the serialport code from dbasnett. The receive (enqueue in this case) routine thread has:

    vb.net Code:
    1. Threading.Monitor.Enter(bufLock)
    2.                     strMessageInBuffer = strMessageInBuffer & Scanner.ReadExisting()
    3.                     Threading.Monitor.Exit(bufLock)

    and then processing routine (timer in this case) thread has:

    vb.net Code:
    1. Threading.Monitor.Enter(bufLock)
    2.                 Response = strMessageInBuffer.Substring(0, 12)
    3.                 strMessageInBuffer = strMessageInBuffer.Substring(13) 'remove first 12 characters from buffer
    4.                 Threading.Monitor.Exit(bufLock)
    Last edited by topshot; Feb 6th, 2015 at 08:00 PM.

  18. #18
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: Issues using BGW for graphing

    I think the problem that you are seeing is due to the use of the 2D singles array. Arrays are reference types and you are passing that array as your UserState object. You are only setting two elements in that array in the bgw thread. When you call ReportProgress and pass that array, an event is raised on the UI thread, but by the time that thread pulls the elements from the arrray, the bwg thread has moved on and changed those values. This is why putting a sleep on the BGW thread "helps" as it provides a chance for the UI thread to process the event handler.

    Try changing your code like this:
    Code:
    Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
       Dim worker As System.ComponentModel.BackgroundWorker = DirectCast(sender, System.ComponentModel.BackgroundWorker)
       Dim i As Single
       Dim GraphData(1, 1) As Single
    
       i = 65
       Dim pt As PointF
    
       Do
           elapsed.Start()
    
           i = i + 0.2
           pt = New PointF(i, MakeSineWave(i))
           worker.ReportProgress(0, pt)
           elapsed.Stop()
           elapsedTime = elapsed.ElapsedMilliseconds
           elapsed.Reset()
           Console.WriteLine(CStr(i) & ":" & CStr(elapsedTime))
    
       Loop Until i > 200
    
    End Sub
    
    
    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
       Dim pt As PointF = CType(e.UserState, PointF)
       Console.WriteLine("Added point at: " & pt.Y.ToString)
       Chart1.Series("Series0").Points.AddXY(pt.X, pt.Y)
    End Sub


    Edit: Too, slow and did not refresh my browser again.

    I see Passel already pointed this out.

  19. #19

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    Quote Originally Posted by TnTinMN View Post
    I think the problem that you are seeing is due to the use of the 2D singles array. Arrays are reference types and you are passing that array as your UserState object. You are only setting two elements in that array in the bgw thread. When you call ReportProgress and pass that array, an event is raised on the UI thread, but by the time that thread pulls the elements from the arrray, the bwg thread has moved on and changed those values. This is why putting a sleep on the BGW thread "helps" as it provides a chance for the UI thread to process the event handler.
    We're closer now. The PointF helped eliminate the missing and doubling of the values as you suggested. I still need to have a Sleep of at least 5 to get the graphing to not be too choppy. It's like they are fighting for priority on the message queue.

    Code:
    190.7981:4
    Added point at: 190.7981
    Added point at: 190.9981
    190.9981:4
    191.1981:4
    Added point at: 191.1981
    Added point at: 191.3981
    191.3981:4
    191.5981:4
    191.7981:4
    Added point at: 191.5981
    Added point at: 191.7981
    Added point at: 191.9981
    191.9981:5
    192.1981:4
    192.3981:4
    Added point at: 192.1981
    Added point at: 192.3981
    Added point at: 192.5981
    192.5981:4
    192.798:5
    192.998:5
    Added point at: 192.798
    Added point at: 192.998
    Added point at: 193.198
    193.198:4
    193.398:4
    193.598:4
    Added point at: 193.398
    Added point at: 193.598
    Added point at: 193.798
    193.798:5
    193.998:4
    194.198:5
    Added point at: 193.998
    194.398:4
    Added point at: 194.198
    Added point at: 194.398
    Added point at: 194.598
    194.598:5
    194.798:4
    194.998:5
    Added point at: 194.798
    Added point at: 194.998
    Added point at: 195.198
    195.198:4
    195.398:5
    195.598:4
    Added point at: 195.398
    Added point at: 195.598
    Added point at: 195.798
    195.798:5
    195.998:4
    196.198:4
    Added point at: 195.998
    Added point at: 196.198
    196.398:4
    Added point at: 196.398
    Added point at: 196.598
    196.598:4
    196.798:4
    Added point at: 196.798
    Added point at: 196.998
    196.998:6
    197.198:4
    197.398:4
    Added point at: 197.198
    Added point at: 197.398
    Added point at: 197.598
    197.598:5
    197.798:4
    197.998:4
    198.198:5
    Added point at: 197.798
    Added point at: 197.998
    Added point at: 198.198
    Added point at: 198.398
    198.398:4
    198.598:4
    198.798:4
    Added point at: 198.598
    Added point at: 198.798
    Added point at: 198.998
    198.998:4
    199.198:4
    199.3979:4
    Added point at: 199.198
    Added point at: 199.3979
    Added point at: 199.5979
    199.5979:5
    199.7979:4
    199.9979:4
    Added point at: 199.7979
    Added point at: 199.9979
    Added point at: 200.1979
    200.1979:5
    Last edited by topshot; Feb 6th, 2015 at 08:22 PM.

  20. #20
    PowerPoster
    Join Date
    Oct 2010
    Posts
    2,141

    Re: Issues using BGW for graphing

    Quote Originally Posted by topshot View Post
    We're closer now. The PointF helped eliminate the missing and doubling of the values as you suggested. I still need to have a Sleep of at least 5 to get the graphing to not be too choppy. It's like they are fighting for priority on the message queue.
    Do you still have the Console.WriteLine statements in there? At the speed that this is processing, those will cause a backup for the debugger to process.

  21. #21

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    Quote Originally Posted by TnTinMN View Post
    Do you still have the Console.WriteLine statements in there? At the speed that this is processing, those will cause a backup for the debugger to process.
    Ah, I obviously do or wouldn't have been able to see the output in my last post. I'll try it without those.

    Perhaps that is also why I don't see any difference in CPU usage between the standard busy wait loop (without a DoEvents but needed to add Update method for the Chart in that case) and the BGW with Sleep(10) added?

  22. #22

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    Removing the Console.WriteLine definitely helped. Goes so fast now it's hard to know if I need to add an Update or Sleep(1) to make sure it's actually redrawing the curve each time, regardless if I'm using the standard busy wait loop or the BGW. I'll go back to my original dummy AD card test so the curve will shift slightly on successive button clicks.

    Edit: Indeed I can tell no difference in the performance of the busy wait loop and the BGW. CPU, time and smoothness all appear to be the same.
    Last edited by topshot; Feb 6th, 2015 at 09:42 PM.

  23. #23
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Issues using BGW for graphing

    What you want to do, as others have hinted at, is to store the successive samples in a buffer - perhaps a circular buffer - then read those samples, asynchronously, in the UI every 100ms or so. The Progress method is never really used, because the UI and background thread are independent of one another. The only connection between the two is a buffer.

    Doing the above gives you full control over the UI smoothness, the data acquisition, and keeps the CPU usage very low. It's possible that you can acquire hundreds of samples on different channels, and display all of them in smooth scrolling charts and keep CPU usage below a few percent.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  24. #24

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    Quote Originally Posted by SJWhiteley View Post
    What you want to do, as others have hinted at, is to store the successive samples in a buffer - perhaps a circular buffer - then read those samples, asynchronously, in the UI every 100ms or so. The Progress method is never really used, because the UI and background thread are independent of one another. The only connection between the two is a buffer.
    Just to verify:
    1) You need to lock the buffer whenever you add or remove data from the buffer per my post in #17, correct? Or perhaps not if using a circular one though you have the risk of an overrun.

    2) You still need a Do or For...Next loop in the Tick event to process everything that has been placed in the buffer so far.

    I'm still curious why the busy wait and BGW appear to work the same on my laptop. It has a 1st gen i5 processor. Maybe it would be more noticeable on the target machine that will be an E7400 I believe.

  25. #25
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Issues using BGW for graphing

    If it's a circular buffer, you would not need to lock it, but as you say, you need to check for buffer overruns: this is where the application specific implementation is the guide rule. Remember, memory is cheap, so a 1Mb or more buffer may be sufficiently large to pretty much ensure the application works under most, normal, circumstances.

    Yes, in your timer tick event you'd loop through all the points you haven't plotted (for next, do while, etc). I usually have a write pointer and a read pointer. The difference between the two indicates how many points are available to plot. This is where the synclock may come in: you can 'lock' the write pointer while you assign it to a local variable.

    They appear to work the same because you are not doing anything else: you are running everything in a 'clinical' environment. It's like turning the heat on full bore in your house, and when it gets too hot, opening the windows. It'll work ok, until it starts raining and snowing, and the tigers want to get in.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  26. #26

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    Quote Originally Posted by SJWhiteley View Post
    Yes, in your timer tick event you'd loop through all the points you haven't plotted (for next, do while, etc). I usually have a write pointer and a read pointer. The difference between the two indicates how many points are available to plot. This is where the synclock may come in: you can 'lock' the write pointer while you assign it to a local variable.
    It would seem you would HAVE to lock it while reading the difference between the two since the BGW would continue to increment the write one.

    It'll work ok, until it starts raining and snowing, and the tigers want to get in.
    LOL. Nice analogy. I did add back in all the DIO calls with desired frequency and such but it may very well work faster with the "demo" board I must use (and my CPU is faster). Though I did not add in the second curve I'll be plotting on the other axis.

  27. #27

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    So I've taken a step forward and then 2 back I suppose.

    Per Passel's suggestion in #14, I'm using a ConcurrentQueue to hold the graph data and using a timer to pull the data from it. That seems to work just fine if I'm only doing single points.

    My issue is back to what TnTinMN said in #18 - since I have 2 lines to graph I wanted to enqueue both points at once so naturally used an array. That doesn't work properly since it's a reference type I'm guessing.

    vb.net Code:
    1. i = 65
    2.         Do
    3.             ULStat = DaqBoard.AInScan(0, 6, 7, 2000, MccDaq.Range.Uni10Volts, MemHandle1, MccDaq.ScanOptions.Default)
    4.             ULStat = MccDaq.MccService.WinBufToArray(MemHandle1, ADData, 0, 7)
    5.             ULStat = DaqBoard.ToEngUnits(MccDaq.Range.Uni10Volts, ADData(0), EngUnits)
    6.             ULStat = DaqBoard.ToEngUnits(MccDaq.Range.Uni10Volts, ADData(1), EngUnits2)
    7.             i = i + 0.2
    8.             pt(0) = New PointF(i, EngUnits)
    9.             pt(1) = New PointF(i, 4 * EngUnits2 + 20)
    10.             cq.Enqueue(pt)
    11.         Loop Until i > 200
    If I break in the loop, cq is never filling (ie, count is always 0). It only has items once the loop is done and they are ALL the very LAST point enqueued rather than what they were assigned in the loop. Again this only happens when using an array. If I make a separate ConcurrentQueue for each graph series then everything is fine again, but that just seems stupid. What do I need to do so I can accomplish something like this?

    vb.net Code:
    1. While cq.TryDequeue(pt)
    2.             Chart1.Series("Series0").Points.AddXY(pt(0).X, pt(0).Y)
    3.             Chart1.Series("Series3").Points.AddXY(pt(1).X, pt(1).Y)
    4.         End While

  28. #28
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,623

    Re: Issues using BGW for graphing

    I would probably just use a structure, with two points in it and enqueue/dequeue the structure.
    Last edited by passel; Feb 10th, 2015 at 04:20 PM.

  29. #29
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    5,623

    Re: Issues using BGW for graphing

    Quote Originally Posted by topshot View Post
    It would seem you would HAVE to lock it while reading the difference between the two since the BGW would continue to increment the write one.



    LOL. Nice analogy. I did add back in all the DIO calls with desired frequency and such but it may very well work faster with the "demo" board I must use (and my CPU is faster). Though I did not add in the second curve I'll be plotting on the other axis.
    You shouldn't have to lock the Write value as it shouldn't matter if it changes while you're looping since you should not be referencing it in your loop.
    He did mention copying the Write value to a local variable, so you snapshot the current value.
    You would do your loop based on the value of the local variable.
    If another value was written to the array while you were looping, you won't access it this time, but will pick it up next time.

  30. #30

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    Quote Originally Posted by passel View Post
    I would probably just use a structure, with two points in it and enqueue/dequeue the structure.
    That was the only way I knew should work so I'm glad you agree.

  31. #31

    Thread Starter
    Frenzied Member
    Join Date
    Dec 2014
    Location
    VB6 dinosaur land
    Posts
    1,191

    Re: Issues using BGW for graphing

    I thought I'd report back that after finally get to test this in the real environment that I'm severely disappointed (and surprised) at the poor performance of the BGW. In fact, if anything it seemed the BGW used just slightly more CPU than the old fashioned way so I gained nothing. Even the charting updates did not occur any better, which is really the only thing that is annoying me right now (and I'll start another thread for that). I used a conditional constant so I can easily switch back and forth between using the BGW or not for the main test loop. The BGW was using a ConcurrentQueue for the charting update (TryDequeue on 100ms timer). Other UI updates were done via ProgressChanged event.

  32. #32
    PowerPoster SJWhiteley's Avatar
    Join Date
    Feb 2009
    Location
    South of the Mason-Dixon Line
    Posts
    2,256

    Re: Issues using BGW for graphing

    I would try plain, simple, threads queueing data to raw arrays, and controlling the synchronization yourself.
    "Ok, my response to that is pending a Google search" - Bucky Katt.
    "There are two types of people in the world: Those who can extrapolate from incomplete data sets." - Unk.
    "Before you can 'think outside the box' you need to understand where the box is."

  33. #33
    Frenzied Member Bulldog's Avatar
    Join Date
    Jun 2005
    Location
    South UK
    Posts
    1,950

    Re: Issues using BGW for graphing

    I'm late to the party here, but I agree on the performance of the BGW. I have an application which concurrently creates data, draws data and also plots a chart. This is ideal for parallel process, but I found putting these tasks onto two timers performed quicker. It also allowed me to adjust the timings (since the create/draw and plot code is quite different in length). So I went around the same loop and ended up back at the start; using timers.


    • If my post helped you, please Rate it
    • If your problem is solved please also mark the thread resolved

    I use VS2015 (unless otherwise stated).
    _________________________________________________________________________________
    B.Sc(Hons), AUS.P, C.Eng, MIET, MIEEE, MBCS / MCSE+Sec, MCSA+Sec, MCP, A+, Net+, Sec+, MCIWD, CIWP, CIWA
    I wrote my very first program in 1979, using machine code on a mechanical Olivetti teletype connected to an 8-bit, 78 instruction, 1MHz, Motorola 6800 multi-user system with 2k of memory. Using Windows, I dont think my situation has improved.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width