|
-
Apr 9th, 2024, 11:36 AM
#1
[RESOLVED] Thread Is Too Fast
I have to run off somewhere, and I haven't had enough time to think about this issue, so I thought I'd toss out a problem in search of a better solution. It's a good problem to have, too.
I wrote a program back around 2003/2005 that...had a LOT of iterations, each of which took a stately amount of time. The result was that the program would take roughly 1.5 days to run to completion. Just recently, I decided to dust off that project and bring it into the modern age. Computers are faster these days, there are more cores, and the program is an example of an embarrassingly parallel application. It REALLY could benefit from threading on multiple cores. No thread will be waiting for any length of time, so threading on a single core never made sense, but threading on multiple cores makes LOTS of sense.
So, I got it working, and have found that it runs too fast. Not a bad problem to have, really, but it messes with the interface. The program is a genetic algorithm. It goes through many thousands of generations in a run. Previously, it went fast enough that it looked pretty good, but the user would be able to use some tools to visualize the evolution over time. Now, it's just too fast, so I'm considering how to change the interface such that the user can still visualize things.
One piece of that is that I need a means to pause a thread. The main loop is running in a BackGroundWorker. My first thought is that I could run that loop inside a sync block. The first step of the loop could be to lock an object, which would then be released at the end of the loop. Of course, this would mean that the lock would be reacquired almost immediately, but there would be an instruction or two during which it would be released. If some of the UI actions wanted to pause the loop, they could also lock that object. This seems like it would work. So long as the UI element held the lock, the BGW would not be able to loop. Once the UI element released the lock, the loop would continue.
Is there any issue with that approach, and is there any other approach I ought to consider to temporarily suspend a thread?
My usual boring signature: Nothing
 
-
Apr 9th, 2024, 01:15 PM
#2
Re: Thread Is Too Fast
If it runs super quick, i.e. like in the blink of an eye, then you can simply store what it does in an array. Then once it finishes, replay the array at a stepped interval using a BackgroundWorker like you suggested. Keep in mind that you probably don't have to do it every time too. You could replay it on command, e.g. a user clicks a "replay build" button that simulates the visualization at a slower pace and even lets them step through it if they want.
That is entirely up to how you think the users would actually use the application. This could be great or it could wind up being a feature that exists, nobody uses, but is all of a sudden required on future rewrites.
-
Apr 9th, 2024, 01:58 PM
#3
Re: Thread Is Too Fast
How about defining a ManualResetEvent object that the backgroundworker checks periodically:
Code:
Imports System.Threading
Public Class Form1
Private resetEvent As New ManualResetEvent(False)
Private backgroundThread As Thread
Private backgroundThreadStarted As Boolean = False
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
backgroundThread = New Thread(AddressOf BackgroundWorker)
End Sub
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If backgroundThread IsNot Nothing AndAlso backgroundThread.IsAlive Then
backgroundThread.Abort()
End If
End Sub
Private Sub StartButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartButton.Click
If Not backgroundThreadStarted Then
' Start the background thread
backgroundThread.Start()
resetEvent.Set()
backgroundThreadStarted = True
Else
MessageBox.Show("Background worker is already running.")
End If
End Sub
Private Sub PauseButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PauseButton.Click
If backgroundThreadStarted Then
' Reset the ManualResetEvent, pausing the background thread
resetEvent.Reset()
Else
MessageBox.Show("Background worker is not running.")
End If
End Sub
Private Sub ResumeButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ResumeButton.Click
If backgroundThreadStarted Then
' Set the ManualResetEvent, allowing the background thread to resume
resetEvent.Set()
Else
MessageBox.Show("Background worker is not running.")
End If
End Sub
Private Sub BackgroundWorker()
Try
While True
' Check if the ManualResetEvent is signaled (set)
resetEvent.WaitOne()
' Perform background work here
Console.WriteLine("Background work in progress...")
' Simulate some work
Thread.Sleep(1000) ' Sleep for 1 second
End While
Catch ex As ThreadAbortException
' Handle thread abort gracefully
End Try
End Sub
End Class
-
Apr 9th, 2024, 02:13 PM
#4
Re: Thread Is Too Fast
The UI that people will mostly be looking at was a "Hollywood" interface that I added after a presentation. It doesn't DO anything useful. It just shows colored lines bouncing around on the screen to visualize the progress of the evolution towards a goal. Replaying that would be possible, and could certainly be of some slight interest, but since it's ultimately useless, I think it would be a feature nobody would use. The real time display was only so that I could have it running in the background for presentations. The other part that would be good to pause for, makes no sense to see in replay. In fact, I had forgotten that it existed, but now that I see it, I see how useful it would be, but not on replay.
@Peter: That's probably simpler than what I was thinking of, so I'll give it a try. It should be able to do what I want pretty easily.
My usual boring signature: Nothing
 
-
Apr 9th, 2024, 03:53 PM
#5
Re: Thread Is Too Fast
Looks like the ManualResetEvent works as I want it to, and I feel it is somewhat better suited to the task than the locking object I was thinking of using.
My usual boring signature: Nothing
 
-
Apr 9th, 2024, 04:45 PM
#6
Re: [RESOLVED] Thread Is Too Fast
Glad it works for you, Shaggy.
Just for anyone who finds this thread, here's the same code again, but using a BackgroundWorker with ManualResetEvent:
Code:
Imports System.Threading
Public Class Form1
Private resetEvent As New ManualResetEvent(False)
Private backgroundWorker As New System.ComponentModel.BackgroundWorker()
Private isPaused As Boolean = False
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Register event handlers for the BackgroundWorker
AddHandler backgroundWorker.DoWork, AddressOf BackgroundWorker_DoWork
AddHandler backgroundWorker.ProgressChanged, AddressOf BackgroundWorker_ProgressChanged
' Enable progress reporting
backgroundWorker.WorkerReportsProgress = True
End Sub
Private Sub StartButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartButton.Click
If Not backgroundWorker.IsBusy Then
' Start the background worker
backgroundWorker.RunWorkerAsync()
resetEvent.Set()
Else
If isPaused Then
MessageBox.Show("Background worker is already running, but paused.")
Else
MessageBox.Show("Background worker is already running.")
End If
End If
End Sub
Private Sub PauseButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PauseButton.Click
' Pause the background worker by resetting the ManualResetEvent
resetEvent.Reset()
Label1.Text = "Background worker is paused."
isPaused = True
End Sub
Private Sub ResumeButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ResumeButton.Click
' Resume the background worker by setting the ManualResetEvent
resetEvent.Set()
isPaused = False
End Sub
Private Sub BackgroundWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
While Not worker.CancellationPending
' Check if the ManualResetEvent is signaled (set)
resetEvent.WaitOne()
' Perform background work here
Console.WriteLine("Background work in progress...")
' Report progress
worker.ReportProgress(0, "Background work in progress...")
' Simulate some work
Thread.Sleep(1000) ' Sleep for 1 second
End While
End Sub
Private Sub BackgroundWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs)
' Update UI with progress information
Label1.Text = e.UserState.ToString()
End Sub
End Class
It needs 3 Button controls "StartButton, PauseButton, ResumeButton," and one Label control.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|