How to do multi-threading?

To do multithreading so that user can interrupt a thread while a threa

  • (2 Pages)
  • +
  • 1
  • 2

21 Replies - 15864 Views - Last Post: 30 September 2008 - 01:33 PM Rate Topic: ***** 1 Votes

#1 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

How to do multi-threading?

Posted 15 September 2008 - 01:01 PM

Hi,

Please review the below code:
Imports System.Diagnostics
Imports System.Threading


Public Class Form1
	Dim pingProc As New Process
	Dim pingThread As New Thread(AddressOf pingProc.Start)


	Private Sub btnPing_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPing.Click

		With pingProc.StartInfo
			.FileName = "ping.exe"
			.UseShellExecute = False
			.RedirectStandardOutput = True
			.RedirectStandardInput = True
			.CreateNoWindow = True
			If cbNumOfTimes.Text = "Continuous" Then
				.Arguments = Me.tbHost.Text & " " & "-t"
			Else
				Select Case cbNumOfTimes.Text
					Case "10"
						.Arguments = Me.tbHost.Text & " " & "-n 10"
					Case "20"
						.Arguments = Me.tbHost.Text & " " & "-n 20"
					Case "50"
						.Arguments = Me.tbHost.Text & " " & "-n 50"
					Case "100"
						.Arguments = Me.tbHost.Text & " " & "-n 100"
				End Select
			End If
		End With
		If cbNumOfTimes.Text = "Contiuous" Then

			pingThread.Start()

		Else
			pingProc.Start()
			btnStop.Enabled = False
			Me.tbResult.Text = pingProc.StandardOutput.ReadToEnd
		End If

	End Sub

	Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click

		pingThread.Abort()
		Me.tbResult.Text = pingProc.StandardOutput.ReadToEnd

	End Sub
End Class



What I want to do is to let user click on stop button to stop the ping process if the ping process is continuous.
I realised a need to do multithreading in order to stop the continuous ping process.
However I wrote the above code and realised the ping process is continuing and i cannot click on any button, my application seems like hang, which means i might have used the multi-threading incorrectly.
Hope to get some suggestions and guidance. Thanks.

Is This A Good Question/Topic? 0
  • +

Replies To: How to do multi-threading?

#2 bflosabre91  Icon User is offline

  • go sabres

Reputation: 105
  • View blog
  • Posts: 1,439
  • Joined: 22-February 08

Re: How to do multi-threading?

Posted 15 September 2008 - 01:47 PM

using thread.abort is very dangerous and i could never get it to work consistently. try looking into the BackgroundWorker. that should have all the functionality you want, and it much easier to work with. heres the msdn link, there are tons of sources on the net for it. search google if you need more info to get started

http://msdn.microsof...oundworker.aspx
Was This Post Helpful? 0
  • +
  • -

#3 magicmonkey  Icon User is offline

  • D.I.C Regular

Reputation: 106
  • View blog
  • Posts: 484
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 16 September 2008 - 06:21 AM

View Postrakyomin, on 15 Sep, 2008 - 01:01 PM, said:

Hi,


What I want to do is to let user click on stop button to stop the ping process if the ping process is continuous.
I realised a need to do multithreading in order to stop the continuous ping process.
However I wrote the above code and realised the ping process is continuing and i cannot click on any button, my application seems like hang, which means i might have used the multi-threading incorrectly.
Hope to get some suggestions and guidance. Thanks.


The process object has all the tools to run async from your main app thread so no need to try and start the process in another thread. You want to simply call process.start. Then in your cancel button call process.kill if I recall. You can also handle events from the process object such as process.exited so your application knows when the process has completed.

In the future if you want to create a new thread make sure you set IsBackground = True. I would also always point it to the address of a method within your app not the address of a method of another class.

		Private t As Threading.Thread
		Private tc As Boolean
		
		Public Sub StartThread

			t = New Threading.Thread(AddressOf ProcessThread)
			t.IsBackground = True
			tc = False 
			t.Start 
		End Sub

		Private Sub ProcessThread()
			Try
				'Do my work here
				For lp As Integer = 1 To 1000
					Threading.Thread.Sleep(100) 'Simulate work
					If tc Then
						'User requested cancel
						Exit For
					End If
				Next
			Catch ex As Threading.ThreadAbortException
				'Cancel did not occur in time and thread has been aborted
				
			End Try
		End Sub

		Private Sub CancelThread()
			tc = True
			If Not t.Join(1000) Then
				t.Abort()
			End If
		End Sub


This post has been edited by magicmonkey: 16 September 2008 - 06:23 AM

Was This Post Helpful? 0
  • +
  • -

#4 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 17 September 2008 - 10:14 AM

Hi MagicMonkey :)

I did not realise you replied in my thread until just now when I login.

I did some research on backgroundworker, and wrote a pingtest program to test if it can work before implementing in my actual project, below is my code.

Imports System
Imports System.ComponentModel
Imports System.Diagnostics

Public Class Form1
	Dim pingProc As New Process
	Private WithEvents pingThread As BackgroundWorker
	Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
		btnStart.Enabled = False
		btnCancel.Enabled = True
		tbResult.Text = ""
		pingThread = New BackgroundWorker
		pingThread.WorkerReportsProgress = True
		pingThread.WorkerSupportsCancellation = True
		pingThread.RunWorkerAsync()
	End Sub
	Private Sub pingThread_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles pingThread.DoWork

		With pingProc.StartInfo
			.FileName = "ping.exe"
			.Arguments = tbHost.Text & " " & "-t"
			.RedirectStandardInput = True
			.RedirectStandardOutput = True
			.UseShellExecute = False
			.CreateNoWindow = True
		End With

		If pingThread.CancellationPending Then
			pingProc.Start()
			Do While pingThread.CancellationPending = true

				Dim i As Integer = 0
				tbResult.Text.Insert(i, pingProc.StandardOutput.ReadLine)
				i += 1
			Loop
		End If
		
	End Sub

	Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
		pingThread.CancelAsync()

	End Sub
	Private Sub pingThread_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) _
	Handles pingThread.RunWorkerCompleted
		btnStart.Enabled = True
		btnCancel.Enabled = False

	End Sub
End Class



Unfortunately it did not work... After I click start no result came out in the text box and it seems the process had not started... :( I wonder which part went wrong in my code...
I will study your code now... :)

This post has been edited by rakyomin: 17 September 2008 - 10:25 AM

Was This Post Helpful? 0
  • +
  • -

#5 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 17 September 2008 - 10:32 AM

I did a bit of modification, tbResult.text still is empty.. and seems like process has never started before...

Private Sub pingThread_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles pingThread.DoWork

		With pingProc.StartInfo
			.FileName = "ping.exe"
			.Arguments = tbHost.Text & " " & "-t"
			.RedirectStandardInput = True
			.RedirectStandardOutput = True
			.UseShellExecute = False
			.CreateNoWindow = True
		End With

		If pingThread.CancellationPending Then
			pingProc.Start()
			Do Until pingProc.StandardOutput.EndOfStream = True

				Dim i As Integer = 0
				tbResult.Text.Insert(i, pingProc.StandardOutput.ReadLine)
				i += 1
			Loop
		End If
		
	End Sub


Was This Post Helpful? 0
  • +
  • -

#6 magicmonkey  Icon User is offline

  • D.I.C Regular

Reputation: 106
  • View blog
  • Posts: 484
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 17 September 2008 - 01:30 PM

I was hinting in my reply that the process object itself run async, there is no need to create a background thread.

Here is how you can do it...
	Private pingProc As New Process
	Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

		With pingProc.StartInfo
			.FileName = "ping.exe"
			.Arguments = "127.0.0.1" & " " & "-t"
			.RedirectStandardInput = True
			.RedirectStandardOutput = True
			.UseShellExecute = False
			.CreateNoWindow = True
		End With

		AddHandler pingProc.OutputDataReceived, AddressOf HandleProcessOutput
	   
		pingProc.Start()
		pingProc.BeginOutputReadLine()

	End Sub

	Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
		If pingProc IsNot Nothing Then
			pingProc.CancelOutputRead()
			pingProc.CloseMainWindow()
		End If
	End Sub

	Private Sub HandleProcessOutput(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs)
		Me.Invoke(New DelegateAddText(AddressOf AddText), New Object() {e.Data})
	End Sub

	Delegate Sub DelegateAddText(ByVal Text As String)
	Private Sub AddText(ByVal Text As String)
		txtOutput.Text &= Text
	End Sub



The code in button1_click starts it
The code in button2_click stops it
The code in handleProcessOutput takes that data from the output stream and calls a delegate to update the text box (you can not update your main thread controls from a background thread it will raise an error so you have to get the main thread to run the code that actually updates the textbox)

hope that helps,
Was This Post Helpful? 1
  • +
  • -

#7 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 18 September 2008 - 01:11 AM

Hi MagicMonkey, thank you again for your help :) It really helps.
I studied your code and tried it on my other project, a project that calls tracert
After trace completed, if user is going to click on cancel button, VB gave an alert:

"InvalidOperationException was unhandled
Process has exited, so the requested information is not available."

The alert pointed to this line >> TraceProc.CloseMainWindow()

Hence I realised I need to disable the start button and enable cancel button while trace is running, and enable back start button and disable cancel button after trace is completed, in order to do this I need to let the application knows has the trace finished or not, to achieve this I wrote the code with "withevents" key word.

Imports System.Diagnostics
Public Class Form1

'Create event handler for this process 
Private WithEvents TraceProc As New Process 

	Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
		btnStart.Enabled = False
		btnCancel.Enabled = True

		With TraceProc.StartInfo
			.UseShellExecute = False
			.CreateNoWindow = True
			.RedirectStandardOutput = True
			.RedirectStandardInput = True
			.FileName = "tracert.exe"
			.Arguments = tbHost.Text
		End With
		tbResult.Text = ""
		TraceProc.Start()
		TraceProc.BeginOutputReadLine()
'invoke Exit event		
Me.OnExited()
	End Sub



Creates OutputDataReceived Events to handle the array list of string generated by tracert.exe (Thanks MagicMonkey for enlightening me the use of Delegate keyword :D)

Private Sub TraceProc_OutputDataReceived(ByVal sender As Object, ByVal e As DataReceivedEventArgs) _
	Handles TraceProc.OutputDataReceived
		Me.Invoke(New DelegateAddText(AddressOf AddText), New Object() {e.Data})
	End Sub
 Delegate Sub DelegateAddText(ByVal text As String)
	Private Sub AddText(ByVal text As String)
		tbResult.Text &= text & vbCrLf
	End Sub



Creates an Exit event, upon exit Start button must be enabled, cancel button must be disabled:

Private Sub TraceProc_Exited(ByVal sender As Object, ByVal e As EventArgs) Handles TraceProc.Exited
		btnStart.Enabled = True
		btnCancel.Enabled = False
	End Sub



Thanks MagicMonkey again :) Upon user clicked on Cancel button, trace suspends; Start Button Enables, Cancel Button Disables
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
		If TraceProc IsNot Nothing Then
			TraceProc.CancelOutputRead()
			TraceProc.CloseMainWindow()
		End If
		btnStart.Enabled = True
		btnCancel.Enabled = False

	End Sub



Create a protected sub OnExited, so that I can invoke Me.OnExited() to forcefully create an Exit event after trace completed
Protected Sub OnExited()

	End Sub
End Class



Ok.. it did not work as expected, the trace finished Start button is still disabled, cancel button is still enabled, however after I clicked cancel button the same alert again, i.e:

"Process has exited, so the requested information is not available.

InvalidOperationException was unhandled"

Ok... So I wrote a Delegate to create a force exit:

Delegate Sub DelegateOnExited()
	Private Sub AddOnExited()
		TraceProc.CloseMainWindow()
	   
	End Sub



and use
 Me.Invoke(New DelegateOnExited(AddressOf AddOnExited))



Still after trace completed, cancel button is still enabled, Start button is still disabled. However this time when I click cancel, no error occur and Start button is enabled... hmm... I wonder how I should I tell my application when trace completed disable cancel button and enable start button...

This post has been edited by rakyomin: 18 September 2008 - 01:27 AM

Was This Post Helpful? 0
  • +
  • -

#8 magicmonkey  Icon User is offline

  • D.I.C Regular

Reputation: 106
  • View blog
  • Posts: 484
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 18 September 2008 - 06:00 AM

View Postrakyomin, on 18 Sep, 2008 - 01:11 AM, said:

Hi MagicMonkey, thank you again for your help :) It really helps.
I studied your code and tried it on my other project, a project that calls tracert
After trace completed, if user is going to click on cancel button, VB gave an alert:

"InvalidOperationException was unhandled
Process has exited, so the requested information is not available."

The alert pointed to this line >> TraceProc.CloseMainWindow()

Hence I realised I need to disable the start button and enable cancel button while trace is running, and enable back start button and disable cancel button after trace is completed, in order to do this I need to let the application knows has the trace finished or not, to achieve this I wrote the code with "withevents" key word.


I think you are missing traceproc.EnableRaisingEvents = True, kinda a bad name from a proprety buy that enables the exit event.

This post has been edited by magicmonkey: 18 September 2008 - 06:01 AM

Was This Post Helpful? 0
  • +
  • -

#9 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 18 September 2008 - 04:41 PM

Yeah I added the line:
 Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
		If TraceProc IsNot Nothing Then
			TraceProc.CancelOutputRead()
			TraceProc.CloseMainWindow()
			'TraceProc.Close()
			TraceProc.EnableRaisingEvents = True
		End If
		btnStart.Enabled = True
		btnCancel.Enabled = False

	End Sub



the problem resolve no invalidoperationexception unhandled alert... :D

anyway how does my application know whether the trace is completed? as i need to disable the cancel button and enable the start button after trace completed.
Was This Post Helpful? 0
  • +
  • -

#10 magicmonkey  Icon User is offline

  • D.I.C Regular

Reputation: 106
  • View blog
  • Posts: 484
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 18 September 2008 - 09:14 PM

View Postrakyomin, on 18 Sep, 2008 - 06:41 PM, said:

Yeah I added the line:
 Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
		If TraceProc IsNot Nothing Then
			TraceProc.CancelOutputRead()
			TraceProc.CloseMainWindow()
			'TraceProc.Close()
			TraceProc.EnableRaisingEvents = True
		End If
		btnStart.Enabled = True
		btnCancel.Enabled = False

	End Sub



the problem resolve no invalidoperationexception unhandled alert... :D

anyway how does my application know whether the trace is completed? as i need to disable the cancel button and enable the start button after trace completed.


You added it in the wrong spot, add it before you start the proccess.
Was This Post Helpful? 0
  • +
  • -

#11 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 19 September 2008 - 08:51 AM

Thank you MagicMonkey for your guidance.

I added like this:
TraceProc.EnableRaisingEvents = True
		TraceProc.Start()
		TraceProc.BeginOutputReadLine()



It works! The application realised that tracert has finished tracing and looked for the TraceProc.Exited event.
Now something happened... VB.net complaint that I cannot access form controls like this:

Private Sub TraceProc_Exited(ByVal sender As Object, ByVal e As EventArgs) Handles TraceProc.Exited
		 btnStart.Enabled = True
		btnCancel.Enabled = False

	End Sub



Thank you for enlightening me about the Delegate keyword.

So I did these:
Delegate Sub DelegateEnableStartBtn()
	Delegate Sub DelegateDisableCancelBtn()
	Private Sub SetStartBtn()
		btnStart.Enabled = True
	End Sub
	Private Sub UnSetCancelBtn()
		btnCancel.Enabled = False
	End Sub



Once delegate and sub routines declared and implemented. I invoke them in TraceProc.Exited event.

 Private Sub TraceProc_Exited(ByVal sender As Object, ByVal e As EventArgs) Handles TraceProc.Exited
		Me.Invoke(New DelegateEnableStartBtn(AddressOf SetStartBtn))
		Me.Invoke(New DelegateDisableCancelBtn(AddressOf UnSetCancelBtn))

	End Sub



Now it works exactly what I wanted this application to :D

After trace completed, Start button enabled, cancel button disabled...

Thank you so much for your guidance MagicMonkey :D
Was This Post Helpful? 0
  • +
  • -

#12 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 19 September 2008 - 09:37 AM

Ok I rewrote the delegates again..

Delegate Sub DelegateSetUnSet(ByVal setUnset As Boolean)
Private Sub setStartBtn(ByVal setBtn As Boolean)
		btnStart.Enabled = setBtn
	End Sub
	Private Sub unsetCancelBtn(ByVal unsetBtn As Boolean)
		btnCancel.Enabled = unsetBtn
	End Sub

 Private Sub TraceProc_Exited(ByVal sender As Object, ByVal e As EventArgs) Handles TraceProc.Exited

		Me.Invoke(New DelegateSetUnSet(AddressOf setStartBtn), True)
		Me.Invoke(New DelegateSetUnSet(AddressOf unsetCancelBtn), False)

	End Sub



This is a better way... haha :P
Was This Post Helpful? 0
  • +
  • -

#13 magicmonkey  Icon User is offline

  • D.I.C Regular

Reputation: 106
  • View blog
  • Posts: 484
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 19 September 2008 - 12:49 PM

Awsome job, your on your way to multi-threaded heaven. There is so much you can do with a background thread to make your application appear more responsive. The hardest part to explain are using delegates to notify the main app thread to update the state of the UI. And you picked it up with ease.

I can teach you a few more tricks for when you don't have paramters you need to pass.


Private Sub MyWorkerThread
   If Me.InvokeRequired Then 'You can actually check to see if you need use invoke
	   Me.Invoke(New MethodInvoker(AddressOf MySubWithoutParms)) 'You can invoke a method without parms in one line!
   End If
End Sub

Private Sub MySubWithoutParms()
   'Update My UI
End Sub




Just another tidbit for you...
Was This Post Helpful? 1
  • +
  • -

#14 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 20 September 2008 - 03:10 AM

Hi MagicMonkey

Thank you for your tips :D

I will be flying to China later for tour...

Hope to continue to receive your guidance after I came back :)
Was This Post Helpful? 0
  • +
  • -

#15 rakyomin  Icon User is offline

  • D.I.C Head

Reputation: 12
  • View blog
  • Posts: 77
  • Joined: 12-September 08

Re: How to do multi-threading?

Posted 29 September 2008 - 06:28 AM

Just came back from China, and beginning to test my application.
I realised the application can only be used once.
after trace was completed, if I clicked start button again, VB.Net will throw InvalidOperation Exeption:
pointing to traceProc.BeginOutputReadLine() with this error: An async read operation has already been started on the stream.

Hence I added a line (i.e. traceProc.CancelOuputRead()) into my traceProc.Exited event

Private Sub traceProc_Exited(ByVal sender As Object, ByVal e As EventArgs) Handles _
	traceProc.Exited
		traceProc.CancelOutputRead()
		Me.Invoke(New DelegateSetUnSet(AddressOf SetStartButton), True)
		Me.Invoke(New DelegateSetUnSet(AddressOf UnSetCancelButton), False)

	End Sub



After trace completed, I clicked start button for a new host, no new data is displaying in my tbResult.Text, it seems like it did not update tbResult.Text.

Any suggestion? Do I need to remove traceProc.OutputDataReceived handler and re-register a new traceProc.OutputDataReceived handler?
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2