Vb.net How can I sleep between multiple tasks in a sub - vb.net

Figured my previous attempt in doing this question was too opinion based, so I'll be more specific.
Intro:
I'm trying to best way possible sleep inbetween multiple "tasks" within a private sub, but my attempts so far have failed me.
I have 9 "tasks" being triggered by a timer timermain and a progressbar pbmain that are working together. At pbmain.value 10 task 1 is being triggered, at pbmain.value 20 task 2 is being triggered and this goes all the way up to pbmain.value 100 and at that point it sets value to 1 and then this whole process loops over and over.
The problem is that this way is not very accurate because some of the tasks take more time than the others, so I'd much rather like to somehow sleep/pause/wait a second or so between each task than use progressbar value.
This is what it looks like
Private Sub TimerMain_Tick(sender As Object, e As EventArgs) Handles TimerMain.Tick
pbMain.Increment(1)
'Channel 1
If cbc1.Checked = True Then
If pbMain.Value = 10 Then
Try
Dim fileTotal As Integer
For Each item As String In lbChannel1.Items
fileTotal += My.Computer.FileSystem.GetFiles(item.ToString, FileIO.SearchOption.SearchTopLevelOnly, (tbExt1.Text)).Count
Next
tbCount1.Text = String.Format("{0}", fileTotal.ToString)
Catch ex As Exception
lbErrors.Items.Add(String.Concat(TimeOfDay & " Error 001: ", ex.Message)) 'Error output
End Try
End If
End If
'Channel 2
'... same as above. Then channel 3, 4, 5, 6, 7, 8 and 9...
To clarify what this does and the whole purpose:
I have so called channels in my form. Each channel is a listbox with items that are paths like \server\share\folder. The code above counts files in those folders if checkbox for that specific channel is checked and gives number output to a textbox tbcount1-9. So yes, the application is monitoring files going in and out of specified folders.
My goal:
Do task 1 -> Complete task 1 and wait one second -> Move to task 2 -> repeat this all the way to task 9 and then loop
I've tried:
Perform step. Did not work well because it looped too fast and fast out of control. I removed pbmain.increment and used performstep between each task.
Thread.sleep. This caused the whole application to sleep for given amout of time instead .
Progressbar marquee mode. I tried, but couldn't figure out how to make it work like my goal.
My question:
How can I complete my goal using something else than progressbar value with a timer...?
Update
Alexander's comment answered my question

You can try with Asnyc/Await Asynchronous Programming with Async and Await
Since your task are working with IO - async/await will be best approach.
Starting new thread only for waiting result from IO is waste of resources(threads).
Private Async Function ExecuteAllAsync() As Task
While True
Await ExecuteTasksAsync()
End while
End Function
Private Async Function ExecuteTasksAsync() As Task
Dim task1 As Task = ExecuteTaskNumberOneAsync()
Await Task.Delay(1000)
Dim task2 As Task = ExecuteTaskNumberTwoAsync()
Await Task.Delay(1000)
'... and so on
'Then wait for all results
Await Task.WhenAll({task1, task2, ...})
End Function
Here is only an idea - of course code above can/must be refactored to "usable" way

Are you just looking for a simple 1 second delay? If so.
Dim Current_Time as Date=Now
While DateAdd(DateInterval.Second, 1, Current_Time)>Now
End While
Now returns the current Date and Time
So I guess your flow would be
Task1->
Delay 1 Sec->
Task 2

Related

parameter thread in vb

First of all, i don't have a good understanding about thread in vb, i tried to get info about it, but i'm still confused about how its work, addressof, the correct implementation and so on. I want to ask about how to create a new thread with parameter so i pass a value from the main thread.
I try to do a loop and each loop create a new thread and do ping. Below is my code:
For i = 10 To 50
Dim worker As New Thread(New ThreadStart(Function()
My.Computer.Network.Ping("192.168.1." & i)
Console.WriteLine("192.168.1." & i)
End Function))
worker.Start()
Next
I realize this is wrong because the result will loop and ping the last value of variable i. So i want to ask about the correct suggestion about it. I will really appreciate if you add a simple explanation for me just to get a better understanding about thread.
Thank you in advance
Your code is almost correct. However, since you are using the same variable for all your created threads. So when your thread starts it more or less contains a pointer to i rather than the value of i. Which means that as your loop progress the value of i change. So when your threads actually start working the loop has completed and the value of i has changed to 51.
To resolve this you have to create a new integer inside the loop. So that the supplied object is unique for every loop. Like so:
Dim x as Integer = i
Then supply x instead of i to the Thread and you are all set.
Here is some reading on the topic:
https://devblogs.microsoft.com/vbteam/closures-in-vb-part-5-looping/
You may also want to try async/await as a better alternative.
Example
Make sure you make the caller async method by using the async keyword:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For i As Integer = 1 To 5
Dim ip As String = $"192.168.1.{i}"
Await Task.Run(Sub() Pinger(ip))
Next
End Sub
Private Sub Pinger(ip As String)
If My.Computer.Network.Ping(ip) Then
Console.WriteLine($"{ip} is alive.")
Else
Console.WriteLine($"{ip} is dead.")
End If
End Sub
The output:
192.168.1.1 is alive.
192.168.1.2 is dead.
192.168.1.3 is dead.
192.168.1.4 is dead.
192.168.1.5 is alive.
Why do you get an ordered sequence? I quote:
The method usually includes at least one await expression, which marks
a point where the method can't continue until the awaited asynchronous
operation is complete.
Please refer to the given link above for more useful details.

Multithreading in vb.net to simulate task

I have a program that is doing one task.
For Example i have one list box containing some links.
And on the other hand my program is opening them one by one but i want it to be done faster
i have used for-each loop for that purpose.
All what i want to do is i wanna give every 2 or 3 link to a different thread or if there is any other solution to make it Faster Kindly tell me.
This is a small piece of code from my program.
For value As Integer = 1 To TextBox1.Text
If (value = TextBox1.Text) Then
Exit For
End If
Dim page As String = "-p-" & value
Extractor.ScrapLinks(txturl.Text + page, lstbox)
lbllinks.Text = lstbox.Items.Count
Next
I don't know what Extractor.ScrapLinks actually do, but it seems that you need to access UI thread and you cannot create multiple UI threads so eventually you will process them sequentially
What you can do to improve the solution is to read the data you want from the UI controls and then process that data on a separate thread, after completion you can fill the results into the UI by invoking some method on the UI thread as shown below
Delegate Sub PerformOperationDel(value As Integer)
Sub PerformOperation(value As Integer)
Dim page As String = "-p-" & value
Extractor.ScrapLinks(txturl.Text + page, lstbox)
lbllinks.Text = lstbox.Items.Count
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
For value As Integer = 1 To CInt(TextBox1.Text) - 1
lstbox.BeginInvoke(New PerformOperationDel(AddressOf PerformOperation))
Next
End Sub
You can use backgroundworkers but notice that you cannot access UI controls in the DoWork but you can access them on work completed (Refer to: Background worker proper way to access UI)
Best of luck

Keeping Application running

I am trying to keep an application open until a file appears. I am using a timer to check the FTP server every 60 seconds (file could take 13 to 15 minutes before it shows up).
The while loop works...but it takes up 50% of my CPU. Trying to figure out another way. I was looking into adding a Windows.Form and using the Application.Run(), but was wondering if the Application.Exit() would close my application.
Public Shared Function CheckStatus(ByVal TaskID As String) As Boolean
_TaskID = TaskID
'Start Timer to Check Query Status Every 10 Seconds
CheckStatusTimer.Interval = 10000
CheckStatusTimer.Enabled = True
CheckStatusTimer.Start()
'Wait for Check Query Status To Complete
While _Status = False
End While
CheckStatusTimer.Stop()
CheckStatusTimer.Enabled = False
Return _Status
End Function
Could placing the CheckStatusTimer.Stop() into completion logic section of my CheckStatusTimer_Tick() Subroutine. How can I prevent the calling function from returning until the timer is stopped?
Thanks
jlimited
The thing you are looking call is called Thread.Sleep():
While _Status = False
System.Threading.Thread.Sleep(500)
End While
This means the thread will check every 500 milliseconds (0.5s) if the Status is different.
This what you need to work with a task in background:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2
Another thing, these lines are wrong:
CheckStatusTimer.Stop()
CheckStatusTimer.Enabled = False
You're repeating, start() method and enabled=true property perform the same thing, also stop() method and enabled=false
Here's a tutorial of how to download a file in background mode
http://msdn.microsoft.com/en-us/library/ms229675(v=vs.110).aspx

Replacing my function with a better one

i'm trying to popup a msgbox everytime the current time is equal to a field in a table in the database i'm using the following code:
For i As Integer = 0 To contentTable.Rows.Count() - 1
UpdateListBoxRec2("Sending content " & i + 1 & " to :")
For j As Integer = 0 To subTable.Rows.Count() - 1
While send = False
If contentTable.Rows(i).Item(1) = DateTime.Now.ToString("hh:mm") Then
UpdateListBoxRec2(subTable.Rows(j).Item(0))
MsgBox(contentTable.Rows(i).Item(0))
send = True
End If
End While
'send = False
Next
Next
this method works but when the debugger is in the while loop ( means when the current time is not yet equal to the time i have in my db table ) i can't use any tool of my windows app untill the debugger gets out of the while loop so i'm searching for a similar method to popup my msgbox in the same condition and to be able to use my tools in the app all the time
please note that i'm using vb.net
any help please :)
You should never sit in an endless loop, like that, on the UI thread. As long as the UI thread is busy, it will be blocked from processing any incoming window messages (e.g. key strokes, mouse clicks). You could sit in a loop like that if you were on a separate thread, but that would be silly. The more sane solution would be to use a timer. For instance, if you drop a Timer component onto your form in the designer, and set it's Interval property to 5000 (five seconds), you can then add the following code:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
For i ...
For j ...
If contentTable.Rows(i).Item(1) = DateTime.Now.ToString("hh:mm") Then
UpdateListBoxRec2(subTable.Rows(j).Item(0))
MessageBox.Show(contentTable.Rows(i).Item(0))
End If
Next
Next
End Sub
Now it will just run that code once every five seconds rather than continuously checking the current time and thereby hogging the UI thread.

Multithreading and error handling in Vb.net

This Question has 2 parts. I am new to multithreading and so I want to firstly check if my logic is correct and then I want to find out how to handel erros in multithreading.
Q1: I have an application that calls SQL database obtaining information from 2 datatables, this info is then combined in a final display. Without multithreading, I call each SQL select to populate a dataset one after the other. With multithreading I call the more complex SQL first as a separate thread and then the less complex SQL call in the main thread second. I am trying to cut down the load time of both by doing them concurently.
(I realise that strictly I should do both as backround tasks to free up the UI, for me its small steps first)
Anyway the code looks little like this
Dim ThreadLoad_Longer_Data As Thread
ThreadLoad_Longer_Data = New Thread(AddressOf Me.Fill_LongerSQL)
ThreadLoad_Longer_Data.IsBackground = True
TThreadLoad_Longer_Data.Start()
'Execute some code here for the second SQL call in main thread
'Then stop the main prosess to wait for the finish of the of the background
ThreadLoad_Longer_Data.join
Im assuming that the .Join statment will infact stop the main thread and will wait for the other one to finish ? Is this correct ?
If so it brings me to the second part.
Q2. What happens if the first thread dosent finish? Like through an error ? How do I handle this situation ?
Thank you
Yes, calling ThreadLoad_Longer_Data.Join will stop the execution of the calling thread (the one that executes the code calling the Join) till the ThreadLoad_Longer_Data ends its execution.
If, inside ThreadLoad_Longer_Data, you have an unhandled exeception, the result is the ending of the thread and thus the resume of the execution of the calling thread.
Sub Main
Try
Console.WriteLine("Start of the main thread")
Dim ThreadLoad_Longer_Data As Thread
ThreadLoad_Longer_Data = New Thread(AddressOf Me.Fill_LongerSQL)
ThreadLoad_Longer_Data.IsBackground = True
ThreadLoad_Longer_Data.Start()
ThreadLoad_Longer_Data.Join
Console.WriteLine("End of the main thread")
Catch x as Exception
Console.WriteLine(x.Message)
End Try
End Sub
Sub Fill_LongerSQL()
Console.WriteLine("Before the exception")
dim y as integer
for x = 0 to 1000000000
y = y + 1
next
Throw new Exception("This is an unhandled exception")
' this will never executed
Console.WriteLine("After the exception")
End Sub