Waiting For Process To Complete - vb.net

Is there any way to pause a process or wait unitl the process is complete before continuing onto the next line of code?
Here is my current process to zip all PDFs and then delete. Currently, its deleting files before the zipping is complete. Is there a way to pause/wait until the process is complete?
Dim psInfo As New System.Diagnostics.ProcessStartInfo("C:\Program Files\7-Zip\7z.exe ", Arg1 + ZipFileName + PathToPDFs)
psInfo.WindowStyle = ProcessWindowStyle.Hidden
System.Diagnostics.Process.Start(psInfo)
'delete remaining pdfs
For Each foundFile As String In My.Computer.FileSystem.GetFiles("C:\Temp\", FileIO.SearchOption.SearchAllSubDirectories, "*.pdf")
File.Delete(foundFile)
Next

Process.Start returns a Process instance. As others have mentioned, you can use the WaitForExit() method, although you should probably use WaitForExit(Integer), which includes a timeout for just in case something goes wrong with the zipping process.
So your code would become something like:
...
Dim zipper As System.Diagnostics.Process = System.Diagnostics.Process.Start(psInfo)
Dim timeout As Integer = 60000 '1 minute in milliseconds
If Not zipper.WaitForExit(timeout) Then
'Something went wrong with the zipping process; we waited longer than a minute
Else
'delete remaining pdfs
...
End If

You can use process.WaitForExit method
WaitForExit can make the current thread wait until the associated process to exit.
Link : http://msdn.microsoft.com/fr-fr/library/system.diagnostics.process.waitforexit(v=vs.80).aspx

There are several WaitForExit methods available.
Check out Process.WaitForExit.
WaitForExit() makes the current thread wait until the associated
process terminates. It should be called after all other methods are
called on the process. To avoid blocking the current thread, use the
Exited event.
Instructs the Process component to wait indefinitely for the
associated process to exit.
WaitForExit(Int32) makes the current thread wait until the
associated process terminates. It should be called after all other
methods are called on the process. To avoid blocking the current
thread, use the Exited event.
Instructs the Process component to wait the specified number of
milliseconds for the associated process to exit.

Related

Threading.Task.Run Submits Twice But Only On Some Calls

Friends: this problem has me flummoxed.
This code submits the same job twice UNLESS I log it!
' optionally log to a textfile before call
If bLog Then LogProcess("Before run")
' this only processes once regardless of
ExecuteSQL($"UPDATE [Process] SET [timesRepeated] += 1, [dateStarted] = '{Now}' WHERE [id] = {iID}")
Dim oBackground As New Background
' this thing spawns two of the some - but not all - jobs!
Dim t1 As Task = Task.Run(Sub() CallByName(oBackground, sProcessKey, CallType.Method, iID))
' optionally log to a textfile following call
If bLog Then LogProcess("After run")
This happens as part of a background processing routine that is called by an internal timer.
I've verified that the timer is only spawned once and only fires once per "heatbeat".
If this routine is called with bLog = True, I get single executions. If bLog = False, SOME processes (sProcessKey) get called twice at the exact same time. I have logging in these routines as well.
Any thoughts?
Thanks in advance.
I hope this helps someone else. It's not a solution, only a work-around:
Since delaying processing by just a bit (via logging in this case) worked, I added a snooze factor, thusly:
If bLog Then
LogProcess("After run")
Else
Thread.Sleep(1000)
End If
This solves the issue, but obviously, delays processing for 1 second.

How to limit the number of processes being spawned at a time?

I am working on a VB.NET Windows Forms application where the user is supposed to be able to determine how many processes the application is allowed to launch at a time.
My current method mostly works but I've noticed that occasionally the application goes over the set amount. I use two global variables for this, _ConcurrentRuns which is 0 at the start of the application, and _MaxConcurrentRuns which is set by the user.
Private _sync As new Object()
' This is called Synchronously
Private Function RunModel() As Boolean
If CancelExectuion Then Return CancelCleanup()
Do While True
SyncLock _sync
If _ConcurrentRuns < _MaxConcurrentRuns Then
Interlocked.Increment(_ConcurrentRuns)
Exit Do
End If
End SyncLock
Threading.Thread.Sleep(50)
Loop
'This is what will launch an individual process and close it when finished
ret = RunApplication(arg)
' The process has been closed so we decrement the concurrent runs
Interlocked.Decrement(_ConcurrentRuns)
Return ret
End Function
The goal is to let only one thread exit the while loop at a time, I'm not able to catch it in the debug mode however in the task manager it will occasionally go 1-3 processes over what it's supposed to use. This makes me assume that somehow multiple threads are getting inside the synclock somehow, but I have no clue how that could be happening.
I will be very grateful for any and all help that can be provided, thanks for taking the time to read my question.
So it appears that my solution works for this, I don't want to delete this question because it might be helpful to somebody else in the future.
Answer: Use better process monitoring software / set priority to high in task manager.

Updating UI while waiting for tasks to finish

I have a vb.net application processing a large amount of data. Due to the memory requirements of the process I am doing this batch-wise, with an overall planned structure as follows:
Do while Start < TotalNumberOfObjects
[cache data used for the upcoming batch]
For i = Start to Stop
[process data using multiple tasks...for example:]
t=taskfactory.startnew(doStuff(i))
TaskList.TryAdd(t.ContinueWith(Sub()
Me.BeginInvoke(DelegateUpdateProgress, {progress})
End Sub))
Next
[Wait for tasks to complete...
Normally I would wait for the tasks using task.waitall(),
but this will cause the UI to wait to update until all tasks are complete]
Start = Stop+1
Stop = Stop+Increment
[clear data from batch that was just completed]
loop
What's the proper way to:
Wait for all the tasks to complete before moving to the next batch?
Update the UI with the overall progress as each task completes?
My target framework is .NET 4.0.
I appreciate any input.
EDIT: Currently I am updating the UI upon completion of each task using task.continuewith() and calling me.beginInvoke to update the form,
TaskList.TryAdd(t.ContinueWith(Sub()
Me.BeginInvoke(DelegateUpdateProgress, {progress})
End Sub))
However, this is incompatible with how I would expect to wait for a list of tasks to complete, task.waitall(tasklist) because calling task.waitall will cause the UI thread to wait to update until all the tasks are complete.
First you need to set up a delegate and then use Dispatcher.Invoke
In the example below, a button is changed from enabled to disable (or the other way around):
Delegate Sub SetRecordButtonEnabledCallback(ByVal Enabled As Boolean)
Friend Sub SetRecordButtonEnabled(ByVal Enabled As Boolean)
Me.btnDGRecord.IsEnabled = Enabled
End Sub
after that all you need to do is call the following code from within your timer to invoke it:
Dim DesiredValue as Boolean = True
Me.Dispatcher.Invoke(New SetRecordButtonEnabledCallback(AddressOf SetRecordButtonEnabled), New
Object() {DesiredValue})
Why don´t you put your routine in a Backgroundworker structure?
So, while you code process data, you´re ready to update any UI component you have.
If necessary, you may also update UI from Backgroundworker, but you need to have some special requirements to do this.
You may consult here:
https://msdn.microsoft.com/en-us//library/ywkkz4s1.aspx

Delay code execution while running program

What is the best way to delay code execution in an application while the program is still running?
I've tried this method:
System.Threading.Thread.Sleep()
But the application does not display until the Sleep() has been executed and I am unsure of alternatives.
Dim t = System.Threading.Tasks.Task(Of Boolean).Run(Function() As Boolean
System.Threading.Thread.Sleep(10000)
Return True
End Function)
Dim ret = t.Result
You need to offload this to another thread, if you call sleep on the current thread then everything including the UI is going to wait until sleep has finished. There are multiple ways to achieve this including the example above.

What Would Cause A Form To Freeze Upon Executing Code

I'm trying to figure why my form freezes up when executing some code. I also can't minimize or move the form. Is it because of the WaitForExit being used in the process?
The below code is tied to a button click.
If Checkbox1.checked = True Then
Call Test()
End If
If Checkbox2.checked = True Then
Goto NextStep
Else
Goto StopProcessing
End If
Here is the test sub I'm calling. Calls an exe with an optional argument.
Using psinfo As New Process
psinfo.StartInfo.FileName = "C:\Temp\Test.exe "
psinfo.StartInfo.Arguments = Arg1
psinfo.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
psinfo.Start()
psinfo.WaitForExit()
End Using
The WaitForExit was added (so I thought) to not process the next statement (next statement being the If statement for Checkbox2) until the process was complete. Is this not the case?
The WaitForExit was added (so I thought) to not process the next statement (next statement being the If statement for Checkbox2) until the process was complete.
When you call WaitForExit, it will block until the process (Test.exe) completes.
Since you're running this on the user interface thread, it will cause your form to "freeze" until the process completes fully.
If you need this to not occur, you would need to wait on a background thread. You could, potentially, move this code into a BackgroundWorker and use it to synchronize with your main window - but you will need to handle "waiting" for the process to finish in a different manner (ie: disable your UI up front, run the process, re-enable when complete).
Note that, with the Process class, another alternative would be to add EnableRaisingEvents on the process, then adding a handler to Process.Exited. This will let you not WaitForExit(), but instead get notified via an event when the process completes.