i made an application for serial communication. for this application i need to set delay time. during this delay time i m doing some other task. So for those task i need to take back control from delay function, for this purpose i am unsing Doevents() function.Its work fine On other OS (XP, Windows7 32/64-bit). But Application.DoEvents() function halt and crash in windows vista.So is there any solution
Private Sub TimeDelay(ByVal DT As Integer)
Dim StartTick As Integer
StartTick = Environment.TickCount()
While ((Environment.TickCount() - StartTick) <= DT)
Application.DoEvents()
End While
'Application.DoEvents()
End Sub
thanks in advance
Try using a BackgroundWorker component instead of calling Application.DoEvents().
Please try System.Threading.Thread.SpinWait(10) after the Application.DoEvents, it might work.
I would recommend putting a "System.Threading.Thread.Sleep(1)" in the loop as well. It might happen because there are too many events pending for Windows to process, therefore ending in high CPU usage.
Sleeping 1 millisecond is very little (actually only 0,001 second). And it would decrease CPU usage dramatically as well, while still allowing the program to remain responsive.
The final code would be:
Private Sub TimeDelay(ByVal DT As Integer)
Dim StartTick As Integer
StartTick = Environment.TickCount()
While ((Environment.TickCount() - StartTick) <= DT)
Application.DoEvents()
System.Threading.Thread.Sleep(1)
End While
'Application.DoEvents()
End Sub
Try running this code:
TimeDelay(1000000)
You will notice that in the process, the program will consume almost 100% CPU with your code, but 0% with mine.
You shouldn't use DoEvents for this purpose.
Create a seperate thread to run the code you have provided. And use a call back (thread completed) to notify when the time has elapsed.
Imports System.Threading
Public Class Tester
Shared WithEvents oSquare As SquareClass = New SquareClass()
Public Shared Sub Main
Dim t As Thread
t = New Thread(AddressOf oSquare.TimeDelay)
t.Start()
End Sub
Shared Sub SquareEventHandler() Handles oSquare.ThreadComplete
Console.WriteLine("Completed")
End Sub
End Class
Public Class SquareClass
Public DT As Integer = 5000 ' 5 seconds (edited thanks to Mathias)
Public Event ThreadComplete()
Public Sub TimeDelay()
Dim StartTick As Integer
StartTick = Environment.TickCount()
While ((Environment.TickCount() - StartTick) <= DT)
thread.sleep(1000)
End While
RaiseEvent ThreadComplete()
End Sub
End Class
Related
I'm new to multi-threading, so I need a general guidance how to proceed.
In a nutshell, I need to call an external webservice thousands of times per second. The response is roughly 1 second per record, which does not work well if I have a million of records to send. So, I've been tasked to use multi-threading to open multiple threads (the number is controlled dynamically) to simultaneously call WS. So, if I can open 100 threads that call WS simultaneously, the task should finish much faster... in theory.
Code is at the bottom, I've cut a lot of unnecessary pieces out of it so please let me know if something makes no sense
The idea behind this code is you would call in Threads.Process, pass DataTable with data that needs to be sent out via WS. This process would run until we processed all records in the data table and _threads (which holds a list of background objects currently working) has zero items in it.
StartThreads would instantiate new background objects if number of simultaneous threads permits and there is new data to be worked on. When a background object completes its task, in order to pass data back to the static object to log its data, it calls Threads.ThreadFinished and passes itself as parameter at which point logging info would be recorded and backgroundobject is removed from _threads.
However, during my testing I noticed that threads are overlaping when calling Threads.ThreadFinished, I tried to offset it with SyncLock to keep it thread safe, but it still does not work 100% fool proof (probably because there are other shared functions still not protected). Since I don't understand this threading very well, I have a feeling there is an easier way of doing this. So, am I on a right track? Should I keep going or switch to a different method? I've researched other multi-threading methods like ThreadPool, but I ended up with this method.
Public Class Threads
Public Shared Sub ProcessRecords(ByVal dt As DataTable)
_threads.Clear()
_startTime = Now
_dt = dt
While Working()
StartThreads()
Thread.Sleep(100)
End While
End Sub
Private Shared Sub StartThreads()
While _threads.Count < Settings.NumberOfThreads AndAlso _rowCounter < _dt.Rows.Count
Dim id As String = GetRandomChar(, 20) ' Generate a random ID for logging purposes
Dim tw As New ThreadWorker(_dt.Rows(_rowCounter), _rowCounter, id, _dt.Rows(_rowCounter)("id").ToString())
_rowCounter += 1
_threads.Add(tw)
End While
End Sub
Public Shared Sub ThreadFinished(ByVal tw As ThreadWorker)
SyncLock tw
Log(tw.Log)
_threads.Remove(tw)
End SyncLock
StartThreads()
End Sub
Private Shared Function Working() As Boolean
Return _rowCounter < _dt.Rows.Count OrElse _threads.Count > 0
End Function
End Class
Public Class ThreadWorker
Private _bw As System.ComponentModel.BackgroundWorker
Private _logDebug As New StringBuilder
Sub New(ByVal dr As DataRow)
_bw = New System.ComponentModel.BackgroundWorker
_bw.WorkerReportsProgress = True
_bw.WorkerSupportsCancellation = True
AddHandler _bw.DoWork, AddressOf bw_Working
AddHandler _bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
_bw.RunWorkerAsync()
End Sub
Private Sub bw_Working(ByVal Sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
' Call webservice ...
_logDebug.AppendLine("Response from WS")
End Sub
Public Sub bw_RunWorkerCompleted(ByVal Sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs)
_logDebug.AppendLine("Job completed")
Threads.ThreadFinished(Me)
End Sub
End Class
EDIT 1:
I think I've solved an issue with threads getting 'lost' - basically I have to SyncLock _threads in all Shared functions (SyncLock tw doesn't seem to do it's job). Still, this feels dirty and hacky at best. I feel like there is a better way to do things. I am currently looking into ThreadPool method, but I am a bit put off by its number of thread limits. I will potentially need to open thousands of threads.
What else I noticed is that the more concurrent threads I open, the longer it takes to get initial response from the WS. For example, if I work 1 record/thread at a time, it takes 1 second to get a response from WS. If I open 100 threads, it takes up to a minute to get a response. I suspect networking is buckling here, or maybe its a windows limitation?
how to automatically disable a button for a period of time in vb.net?
my project is voting management using vb.net and Sql server .my voting starts only from 9 am-10 am .so the button which i log in should automatically disable before and after the given time.
Run a Thread on start-up which from this point on should loop forever. Check the DateTime.Now to check what time it is currently. Enable and Disable it if the time is between your allotted times. Then calculate how long you need to wait before the end of the window, put the thread to sleep for that amount of time.
Edit: example code
Make sure you include this at the top. Imports System.Threading
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim myThread As System.Threading.Thread
myThread = New System.Threading.Thread(AddressOf ThreadLoop)
myThread.Start()
End Sub
Private Sub ThreadLoop()
While True
Dispatcher.Invoke(
Sub() myButton.IsEnabled = (DateTime.Now.Hour = 9))
Thread.Sleep(10000) ' This implementation just rechecks every 10 seconds
End While
End Sub
Note: This solution automatically updates the UI when the time changes.
In your form/page loading, use DateTime to get the current hour:
Dim currentDate As System.DateTime
Dim currentHour As Integer
currentDate = Date.Now()
currentHour = currentDate.Hour
If currentHour = 9 Or currentHour = 10 Then
button.Visible = False
Endif
I'm trying to create a class that will create a Relogin after certain time but after the first Relogin it keeps populating. Heres my Code:
Private Shared timer As Timer
Public Shared Event DoSomething As Action(Of Integer)
Private Shared _timesCalled As Integer = 0
Public Shared Sub Start()
AddHandler DoSomething, AddressOf EventHandler
timer = New System.Threading.Timer(AddressOf timer_Task, Nothing, 0, 1000)
End Sub
Public Shared Sub [Stop]()
timer.Dispose()
End Sub
Private Shared Sub timer_Task(State As Object)
_timesCalled += 1
If _timesCalled = 15 Then 'Should Raise event every 15s
RaiseEvent DoSomething(_timesCalled)
End If
End Sub
Private Shared Sub EventHandler(ByVal EventNumber As Integer)
My.Application.Dispatcher.Invoke(New Action(AddressOf OpenLogin))
End Sub
Private Shared Sub OpenLogin() 'This event fires multiple times after the first Event
Dim x As New MainWindow
x.ShowDialog() 'Dialog stops code from continuing.
x = Nothing
_timesCalled = 0
End Sub
Open_Login() fires multiple times after the first or second time. Doesn't seem to cause the same problem when I replace "MainWindow" object with a messagebox. Please Help. Thank you.
Notwithstanding the fact that your issue seems to be solved - using an unsynchronised counter is not a reliable way to have an event fired every predetermined period.
The timer event itself fires from a separate .NET managed thread and subsequently, the _timesCalled variable can be accessed from multiple threads. So it is possible that while you are re-setting _timesCalled=0 from your main thread another thread from the default threadpool is about to overwrite this with _timesCalled=14.
In your specific example it is simpler and more straightforward to reschedule the timer event after you’ve finished handling one. That way you can also account for the time it took you to process the event and the timer inaccuracies and lag.
Public Shared Sub Start()
...
' assuming this runs only once
timer = New System.Threading.Timer(AddressOf timer_Task, Nothing, 15000, Timeout.Infinite)
End Sub
Private Shared Sub timer_Task(State As Object)
RaiseEvent DoSomething(_timesCalled)
End Sub
Private Shared Sub OpenLogin()
Dim x As New MainWindow
x.ShowDialog()
x = Nothing
' Reschedule the timer again here, adjust the 15000 if necessary, maybe prefer timer.ChangeTime(...) instead
End Sub
Figured out it was my coding. Everytime MainWindow would load it would run Start() creating a new instance of Timer. Correct issue. Thanks for viewing
My case is I have the following method that uses SyncLock to ensure the writing of file by one thread at a time.
Private Shared lockThis As New Object
Public Sub Process()
SyncLock lockThis
File.AppendAllText("c:\jamo\foo.txt","foo")
End SyncLock
End Sub
I'm using many threads running at time:
Public Sub CreateThreads()
Dim trd as Thread
Dim X as Integer = 10
For i as integer = 1 to X
trd = New Thread(AddressOf Process)
trd.Start()
Next Sub
End Sub
My problem is when X is big (like 500), one o more threads write to file at same time. Why is happening this?
I don't have proof, but it could be telling the truth. If any other process opens the file without sharing it, with 500 or more threads attempting to open it, it is likely the file will be locked for one of them...
How do I call a function every x minutes.
I assume I'd have to add a timer to the form?
here is a simple example:
Public Class SampleCallEveryXMinute
Private WithEvents xTimer as new System.Windows.Forms.Timer
Public Sub New(TickValue as integer)
xTimer = new System.Windows.Forms.Timer
xTimer.Interval = TickValue
End Sub
Public Sub StartTimer
xTimer.Start
End Sub
Public Sub StopTimer
xTimer.Stop
End Sub
Private Sub Timer_Tick Handles xTimer.Tick
SampleProcedure
End Sub
Private Sub SampleProcedure
'SomeCodesHERE
End Sub
End Class
USAGE:
Dim xSub as new SampleCallEveryXMinute(60000) ' 1000 ms = 1 sec so 60000 ms = 1 min
xSub.StartTimer
Yes, you could add a timer to the form, and set its interval to x*60000, where x is the number of minutes between calls.
Remember that the timer runs on the UI thread, so don't do anything intensive in the function. Also, if the UI thread is busy, the timer event will not fire until the UI thread finishes whatever event it is currently processing. If your function is going to be CPU-intensive, then consider having the timer start up a background worker
If you require a longer time period between function calls (ie, one thats too big for a timer interval) then you could have a timer function that fires every minute, and increments a counter until the desired amount of time has passed, before going on to call the function.
ALTERNATIVE 1
Here is good guide to use the Timer Control in VB.net.
The advantage is that you don't have to worry about modifying UI objects from non UI thread.
ALTERNATIVE 2
Another alternative is to spawn another thread and do the work and sleep the remaining x minutes.
The advantage here is that if your function doesn't touch UI objects your application will remain responsive to user input while the function is being called
Private Sub Form_Load()
_timer.Enabled = True
End Sub
Private Sub _timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
ListBox1.Items.Add(DateTime.Now.ToLongTimeString() + "," + DateTime.Now.ToLongDateString())
End Sub