Limit The Time A Routine Can Run - VBNET - vb.net

I'm trying to fill a dataset, but I want to limit the amount of time the system has to fill this dataset to 30 seconds.
I have tried (as suggested elsewhere on SO):
Dim T As Date = Date.Now
da.Fill(ds, "DATASET")
Do
If (Date.Now - T).TotalSeconds >= 30 Then
Main.VIEW_Title.Text = "Error In Connection..."
Exit Sub
End If
Exit Do
Loop
But the system just hangs anyway during the da.Fill(ds, "DATASET") section and doesn't ever exectute the "Error In Connection" message. It doesn't matter if I put the line inside the DO either, because it stops there. What I need is for it to execute the fill command, and then if it doesn't complete in 30 seconds, to allow me to handle that error.
Thanks

Unfortunately, that's not so easy.
What you can do is:
Start a background thread and do the fill operation in that thread.
In the main thread, wait for 100ms, check if the new thread completed, repeat at most 300 times.
Now the real problem is: What do you do if the main thread determines that the background thread has not finished after 30 seconds? DataAdapter.Fill does not provide a method to gracefully interrupt the operation, so you'll have to let it continue in the background.
This also means that you must use a separate data connection in the background thread, since the ADO.NET classes are not thread-safe.
I'd rather suggest a different approach: A data selection operation taking more than 30 seconds implies that either:
you select too much data (there's really no use showing 1 million rows to the user) or
your query needs optimization (such as a well-placed index).
Thus, I suggest to fix the root cause instead of using complicated workarounds to cover-up the symptom.

Related

Multithreading Webbrowsers

I am currently making a vb program that i plan to make very big. I have a decent knowledge of visual basic but today i came across something i do not understand. Because of the huge size of my program , i decided to try and keep the program as organized as possible by putting specific subs in modules. These subs consist of httprequest , webbrowsers(control), webclients and alot of loops. In order to prevent these subs from lagging my main application i thread them using threading.thread and i start them from my main form. But this leads to two problems.
Problem 1: The threads cannot in any way interact with the main form.
Once the a httprequest or webclient collects the information from my desired website, i am trying to make it add the info to a listbox in my main form, So what i did is it typed
Msgbox("Info Sent")
form1.listbox1.items.add(String)
The first messagebox will show but although the code right under it runs, nothing is added to the first forms listbox.I am not using delegates to transfer the information, instead, although its not a good habit, i am using checkforillegalcrossovers.
Problem 2: Threading with a webbrowser.
Threading with a webbrowser using threading.thread also does not work because it causes an active x error. After looking it up i found that a solution was to use a single threaded apartment but this would not work because i may need multiple threads running off the same sub at once.
One solution that i have found to this problem is creating another form completely and setting it invisible, and since the form is its own thread i do not need to use threading.thread , but the problem comes when i am trying to create multiple threads, or else i can somehow dynamically create the threads and put the subs inside of it programically this method wont work And even if it does i feel that it is sloppy so i will leave this for one of two last resorts.
The other solution is the most simple one in which i just put all of the code in the main form, but if i keep on doing that form1 is gonna become huge and sloppy, doing this wont solve the webbrowser problem either and even when using regions i still feel that something that 1000+ lines deserves its own class.
There must be some solution out there that solves these problems. Any help would be appreciated, Thanks.
I checked my code for updating the progress bar, and using a single thread with synclock will NOT work. They way I make it work is perform the step of the pbar each time after a thread is started as I have limited total threads (say less than 5 threads). Thus, even the progress bar steps before the threads are finished, but it will not progress further before new threads started. It is not 100% accurate but it more or less telling the progress
'update the progress bar
some_form.PBar1.PerformStep()
' This while loop is to count the existing running thread,
' and determine whether new thread should start
While 1
Dim t2 = New System.Threading.Thread(Sub() WaitForPermission())
t2.Start()
t2.Join()
If proceed_gen Then
Exit While
End If
End While
'Start doing what I need to do
Dim t1 = SomeSub()
t1.Start()
'End of code, as VB doest not have thread.detach()
Correct me if I am wrong, but you probably have to use a background worker. I know this is annoying, but this is the limitation of VB.net.
Or, you can have something like this (pseudo code, not tested)
structure some_struct
'define the strings you want to update, and their status such that
'main() knows if you need to update the stuff to the form
' You can also put how many threads are running, and the status of each thread,
'such that the main knows if all threads are completed
end structure
sub your_sub()
'Manipulate the website, and update the data structure with
'proper stuff you need
end sub
sub main(){
dim t1 = New System.Threading.Thread(Sub() your_sub())
t1.start()
' I am listing only one threads here, but start as many as you want
'check if there are strings that you need to update to the form
while 1
'check if there are any stuff you want to update from the data structure.
' Make sure you use synclock on the data structure, so each thread won't fight each other on accessing the data struct
dim should_update as boolean = false
should_update = 'Something thatyou should implement to judge whether you should update the form.
'You can start a thread and join it so the thread won't fight with other threads for accessing the data structure
dim some_string as string
if should_update
some_string = 'You may also need a thread to join to get the stuff you need. Dim the string as an array if it is required.
'You can also try pass by ref
'if you need to use thread to access the data structure to know if you need to update the form
form1.listbox1.items.add(some_string )
end if
end while
end sub
This is an ugly solution, but it will help you do the job...

VBA - Updating Progress Bar while running SQL Query

I have a progress bar that updates based on the line:
Call ProgressBar(X)
Where X indicates the percentage that the bar displays as 'complete'.
I've roughly calculated various time intervals throughout the code and placed the line several places throughout. It's at the point where it runs quite smoothly for the majority of the code but only half of the bar, with the problem being a forced jump from 10% to 60%.
I'm using an ADODB connection to run a SQL query in the code (I can't take it out of the code because I'm passing variables through it). The jump from 10 to 60 is either side of the line where I'm executing the query
Set rs = conn.Execute(QryND)
where rs is defined as ADODB.Recordset and conn as ADODB.Connection.
I guess ideally what I'm after would be to know if it's possible to say:
Call ProgressBar(10)
'code to the effect of: "in x seconds, execute the next line but in
'the meantime continue with the code
Call ProgressBar(20)
'code to the effect of: "in 2x seconds, execute the line but in the
'meantime continue with the code
Call ProgressBar(30)
Set rs = conn.Execute(QryND)
Or something to that effect.
Alternatively a means of running the query in the background and continuing the code up to a point. Eg
Call ProgressBar(10)
'instruct to run in backrgound:
Set rs = conn.Execute(QryND)
Call ProgressBar(10)
'wait x seconds
Call ProgressBar(20)
'wait x seconds
.
.
.
'Stop running query in background (in case it hasn't finished)
Do either of these sound possible?
Running background queries is not recommended as they can run your code into errors. What you can actually do is leave the StatusBar the f* alone and check it with while loops (or at regular intervals) , i.e. does it fetch the connection, run or is it finished.
What you can do is create an ActiveX object to display whatever you wanted to tell, even up to fancy load bars and multiline feedback.
You cannot really have asynchronous processes in a single-threaded application unless you call outside scripts to execute them.

Async event handler - flycapture from PointGrey

I am using Point Grey's FlyCapture API to drive some cameras.
In a public class, I implemented all the starting and initializing code ; in the following _cam refers to a ManagedGigECamera.
Because I have 16 cameras, I want the code to be as fast as possible, so I wanted to use tasks.
Here is the code I use:
_cam.StartCapture(AddressOf OnImageGrabbed)
.../...
Public Sub OnImageGrabbed(ByVal raw_image As ManagedImage)
Dim t As Task = Task.Run(Sub()
'save image to disk or whatever
End Sub)
t.Wait()
End Sub
The above gives -sort of- satisfaction. By viewing image timestamps, I can see that some images are saved seconds after they are grabbed, and even some images are skipped altogether...
I wanted to make sure each call to OnImageGrabbed would start a new task, and tried the following, but it crashes right away with 'object not set to an instance of an object' (can't really debug, the code is running on a remote machine)
_cam.StartCapture(AddressOf OnImageGrabbed)
.../...
Public Async Sub OnImageGrabbed(ByVal raw_image As ManagedImage)
Await Task.Run(Sub()
'save image to disk or whatever
End Sub)
End Sub
All in all, my questions are:
how can I run an event handler asynchronously ?
why, using the first code, do I get (what appears to be) random delays between each call
to OnImageGrabbed ? I mean the differences in time between image timestamps is never the same, and tend to increase on the long run (first few images are almost synchronized, but after 1 minute or so, each image is separated by more and more time). Memory leak ? GC ?
Thanks in advance for any hint !
EDIT:
In the end I changed the way the system works: I fire a software trigger on each camera using a timer, and each trigger is fired 'in parallel':
Parallel.ForEach(Of ListOfCameras)(SingleCamera,
Sub(aCamera, loopstate, num)
aCamera.FireTrigger()
End Sub)
Starting a task and then immediately blocking on it (via Wait) nets you nothing. You may as well just run the saving-image code directly.
The second example is actually asynchronous. You're probably getting an exception because the ManagedImage argument or one of its child objects is being disposed. Remember that the code raising the event has no idea that your code is asynchronous; it's up to you to copy out what you need from the event arguments if you're going to use it asynchronously.

Turning For loop in Backgroundworker into multithreader

I have a background worker where I currently am running a setup to loop through and send the http commands to these devices to update their firmware. Currently it's very slow, looping though each one and sending it.
My first question is, how can I multithread this so increase the speed? Usually I would make a task per device, add to a task array, and do a "wait all". But the device numbers could get up to 300 here so I want to limit it to a smart amount and do it dynamically.
And my second question is, is it wise to do so in the back groundworker that is already a thread (so I can show the progress bar)? Or is there another way to do it that is smarter?
Here's the current setup:
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker.DoWork
'loop through devices
For Each assignment As FirmwareAssign In assignList
'firmwareassign is a struct with credentials for http, ip address, and device brand as strings
'Send Update Request
Select Case assignment.devcebrand.tolower
Case "brand1"
Logstatement += brand1.updateFirmware(assignment, assignment.deviceipaddress)
Case "brand2"
Logstatement += brand2.updateFirmware(assignment, assignment.deviceipaddress)
Case "brand3"
Logstatement += brand3.updateFirmware(assignment, assignment.deviceipaddress)
End Select
'don't worry, not real names of my classes
Next
End Sub
These functions are network based. They will grab the new firmware image, and send it to the ip address over the network. So I also want to limit it since we don't want the bandwidth to go nuts. Then it will add it to the logstatement (a string) to display at the end for the user to know if something went wrong.
Since you are sending these across the network and your bottle-neck is likely the network, running multiple threads will not speed it up, if anything it will slow down.
If this is not the case, or you want to test this anyway, here are your 2 answers:
1: If you are already doing a collection, in this case a task array, your are almost there. What I do is stick another loop in your current loop and run while the array/collection length is greater that X (maybe 10 in your case) and in that loop, check the thread status and remove any of those that are complete. This will make it jump out of the inner loop and add more threads until you hit X again.
2: While I don't think there is anything that prevents you from running threads from other threads, the logistics of getting updates back to the GUI might be a nightmare. I would spawn the threads from your main thread which makes progress updates real easy.

How to use the same class accross multiple threads and return a variable

My apologies in advance if this has already been answered, but every search I have done does not come close to what I need. Also, this is all pseudo code.
Here is the situation: I created a form (targeting DOT NET 3.5) that does a loop on a gridview recreating a class and runs the code. After the code runs, there is a local variable on the class that gets updated and allows me to use it and the process repeats. Something like this:
For x as Integer = 0 to Me.txtTextBox.Lines.Count - 1 'Can be in the hundreds
Dim objMyClass as MyClass = New MyClass(Me.DatagridView1.Rows(x).Cells(0).Value)
if objMyClass.Start() = True then
'Do my thing with objMyClass.LocalLongVariable
End If
Next
This works just fine, but takes literally days to complete. The last time I ran this it took like 6 days, 7 hours and 40 something minutes to complete and barely bumped the CPU usage.
So, now I want to use MulitThreading to run several of these instances at the same time. I have not been able to get this to work. Everything I try returns different values every time I run it (and it should not). I believe that the threads are accessing the local variable across other threads and are incrementing at will. And SyncLock locks up the entire program. I have also tried adding a custom event that fires when the process is completed and executes a delegate on the Main form, but that has not worked either.
Now, my question is simple: How can I run multiple threads using the same base class (passing a unique string variable) and have the local class variable produce the correct results back to the UI? (And, from what I have been reading, the BackgroundWorker class in not suitable for this many threads (like hundreds); correct me if I read it incorrectly please)
I am looking for something like:
Dim thrd(Me.txtTextBox.Lines.Count) as Thread
Dim objMyClass(Me.txtTextBox.Lines.Count) as MyClass
For x as Integer = 0 to Me.txtTextBox.Lines.Count - 1
thrd(x) = new Thread (Sub()
objMyClass(x) = New MyClass(Me.GridView1.Rows(x).Cells(0).Value
If objMyClass.Start() = True Then
'Do my stuff here (maybe call a delegate??)
End If
End)
thrd(x).IsBackground = True
thrd(x).Start()
Next
Any help/advice on how to proceed will be greatly appreciated. And, if you know of any examples of your suggestion, please post the code/link.
The solution was, in fact, Synclock. My issue was that I was locking the wrong object, objMyClass, instead of the current Me AND I was failing to use Monitor.PulseAll(). Also, I switched to using the ThreadPool.QueueUserWorkItem(AddressOf objMyClass, args) and also used SyncLock on my custom event raised when the thread completes. It's a whole lot easier!! Thanks!!