multiple threading in nested loop in vb - vb.net

I'm new to threading concept in VB .NET and I have two nested for each loops and I want a new thread every time loop executes. What I'm doing here is that I'm calling a function every again and again with different parameters with the help of two nested loops. And what I want is every time I call that function that get executed as a new thread.
Here's my Code -
Dim threadCount As Integer = 1
Dim theradArray(100) As System.Threading.Thread
Dim copyProcessID As Integer = 0
For Each dest_path As String In destList
If Directory.Exists(dest_path) Then
'copy process
Dim copyProcessOBJ As copy
For index = 0 To sourceList.Count - 1
source = sourceList(index)
If source.isChecked = True Then
copyProcessID += 1
If cliRadioButton.Checked Then
cmdCopy(source.Path, dest_path)
Else
ProgressReports.Show()
copyProcessOBJ = New copy
threadCount += 1
theradArray(threadCount) = New _System.Threading.Thread(AddressOf copyProcessOBJ.guiCopy)
theradArray(threadCount).Start()
copyProcessOBJ.guiCopy(source.Path, dest_path, copyProcessID)
End If
End If
Next
Here I have a class named copy and a sub 'guiCopy' Inside that
I'm making new instance of that obj every time in loop. likewise that I want a new thread.
But I have a problem which says initializes new instance of Thread class.
I'm sorry I know it's my fault that I don't know how to implement it.
Just need Help

Dim threadCount As Integer = 1
Dim theradArray(100) As System.Threading.Thread
Dim copyProcessID As Integer = 0
Dim threads As List(Of System.Threading.Thread) = New List(Of System.Threading.Thread)
For Each dest_path As String In destList
If Directory.Exists(dest_path) Then
Dim thr As System.Threading.Thread = New System.Threading.Thread(AddressOf yourfunction)
threads.Add(thr)
threads.LastOrDefault().Start()
End If
Next
Private Sub yourfunction()
Dim copyProcessOBJ As copy
For index = 0 To sourceList.Count - 1
source = sourceList(index)
If source.isChecked = True Then
copyProcessID += 1
If cliRadioButton.Checked Then
cmdCopy(source.Path, dest_path)
Else
ProgressReports.Show()
copyProcessOBJ = New copy
threadCount += 1
theradArray(threadCount) = New _System.Threading.Thread(AddressOf copyProcessOBJ.guiCopy)
theradArray(threadCount).Start()
copyProcessOBJ.guiCopy(source.Path, dest_path, copyProcessID)
End If
End If
End Sub
Next

Related

Output random lines from a large document to a TextBox

I'm trying to make a program that reads a large document, for example the bible, and outputs multiple random lines. I can get it to output one random line, but no others.
The end goal is to have a user input to determine how many lines are displayed.
Here's my code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' Dim howmanylines As Integer
' howmanylines = InputBox("how many lines for paragrpah", "xd",,,)
'Dim count As Integer = 0
' Do Until count = howmanylines
Dim sr As New System.IO.StreamReader("C:\Users\Dumpster Fire\Desktop\bible.doc")
Dim sr2 As New System.IO.StreamReader("C:\Users\Dumpster Fire\Desktop\bible.doc")
Dim sr3 As New System.IO.StreamReader("C:\Users\Dumpster Fire\Desktop\bible.doc")
Dim xd As Integer = 0
Dim curline As Integer = 0
Dim random As Integer = 0
Do Until sr.EndOfStream = True
sr.ReadLine()
xd = xd + 1
Loop
sr.Dispose()
sr.Close()
Randomize()
random = Rnd() * xd
Do Until curline = random
TextBox1.Text = sr2.ReadLine
' curline = curline + 1
Randomize()
random = Rnd() * xd
TextBox1.Text = sr3.ReadLine
curline = curline + 1
' count = count + 1
Loop
End Sub
End Class
A couple of things I would suggest to improve your code.
Implement Using. This will ensure that the StreamReader is disposed of when finished. It saves you having to remember and it's less lines of code so improves readability.
I would consider using Integer.TryParse:
Converts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the conversion succeeded.
You only need to use one StreamReader and add all the lines to a List(Of String).
Use a StringBuilder to add your lines too and then output this to the TextBox at the end. Note that you will have to import System.Text to reference the StringBuilder class.
Use Random.Next:
Returns a random integer that is within a specified range.
The end result would be something like this:
txtLines.Text = ""
Dim howManyLines As Integer = 0
If Integer.TryParse(txtUserInput.Text, howManyLines) Then
Dim lines As New List(Of String)
Using sr As New StreamReader("C:\test\test.txt")
Do Until sr.EndOfStream()
lines.Add(sr.ReadLine)
Loop
End Using
Dim sb As New StringBuilder
Dim rnd As New Random()
For i = 0 To howManyLines - 1
Dim nextLine As Integer = rnd.Next(lines.Count - 1)
sb.AppendLine(lines(nextLine))
Next
txtLines.Text = sb.ToString()
End If
You would ideally place this code on a button click event.

vb.net multithreading with multiple threads in a For..Next Loop

Hi folks I have the code below which i wanted to use all my processors cores. Originally, the code in the sub chekFileDupe was all within the For..Next loop in SearchForDupes sub and worked just fine on one thread. I'm a bit stuck as to create 4 threads that execute the checkFileDupe code so that i can check 4 items at a time, then wait till all 4 threads have completed. Then carry on with the next iteration of the loop.
This is the original code
Private Sub SearchForDupes()
Me.Refresh()
Dim totalrecords As Integer = dvSortedSearchResults.Count
Label1.Text = "Searching for duplicates"
Label1.Refresh()
dvSortedSearchResults.Sort = DataSortOrder
For i = 0 To totalrecords - 6 Step 4
Dim TrackDifference As Integer
Dim originalTrack, originalArtist, trackToCompare, artistToCompare As String
If i / 10 = CInt(i / 10) Then
Label2.Text = i.ToString + " of " + totalrecords.ToString
Label2.Refresh()
End If
originalArtist = mp3record(i, "Artist")
originalTrack = mp3record(i, "Track")
Dim ii As Integer = i + 1
While ii < totalrecords - 2
artistToCompare = mp3record(ii, "Artist")
trackToCompare = mp3record(ii, "Track")
TrackDifference = Difference(originalTrack, trackToCompare)
dvSortedSearchResults(ii).Item("Difference") = TrackDifference
'dgvSearchResults.Rows(ii).Cells("Difference").Value = trackdiff
If Difference(originalArtist, artistToCompare) < 6 Then
TrackDifference = Difference(originalTrack, trackToCompare)
If TrackDifference < 4 Then
dvSortedSearchResults(i).Item("Difference") = 999
dvSortedSearchResults(ii).Item("Difference") = TrackDifference
dvSortedSearchResults(ii).Item("chkdupe") = True
End If
Else
Exit While
End If
ii = ii + 1
End While
Next
Label2.Text = ""
Label1.Text = ""
End Sub
This is the first attempt at multithreading - probably naive but hey - everyone's new at something
Private Sub SearchForDupes()
'Dim query = (From record In dvSortedSearchResults Where record.Artist = "Abba" Select record).ToList
Me.Refresh()
Dim totalrecords As Integer = dvSortedSearchResults.Count
Label1.Text = "Searching for duplicates"
Label1.Refresh()
dvSortedSearchResults.Sort = DataSortOrder
Dim params(2) As Integer
For i = 0 To totalrecords - 6 Step 4
params(2) = totalrecords
params(1) = i
thread1 = New System.Threading.Thread(Sub() checkFileDupe(params))
thread1.Start()
params(1) = i + 1
thread2 = New System.Threading.Thread(Sub() checkFileDupe(params))
thread2.Start()
params(1) = i + 2
thread3 = New System.Threading.Thread(Sub() checkFileDupe(params))
thread3.Start()
params(1) = i + 3
thread4 = New System.Threading.Thread(Sub() checkFileDupe(params))
Next
Label2.Text = ""
Label1.Text = ""
End Sub
Private Sub checkFileDupe(params As Array)
Dim i As Integer = params(1)
Dim totalrecords As Integer = params(2)
Dim TrackDifference As Integer
Dim originalTrack, originalArtist, trackToCompare, artistToCompare As String
If i / 10 = CInt(i / 10) Then
Label2.Text = i.ToString + " of " + totalrecords.ToString
Label2.Refresh()
End If
originalArtist = mp3record(i, "Artist")
originalTrack = mp3record(i, "Track")
Dim ii As Integer = i + 1
While ii < totalrecords - 2
artistToCompare = mp3record(ii, "Artist")
trackToCompare = mp3record(ii, "Track")
TrackDifference = Difference(originalTrack, trackToCompare)
dvSortedSearchResults(ii).Item("Difference") = TrackDifference
'dgvSearchResults.Rows(ii).Cells("Difference").Value = trackdiff
If Difference(originalArtist, artistToCompare) < 6 Then
TrackDifference = Difference(originalTrack, trackToCompare)
If TrackDifference < 4 Then
dvSortedSearchResults(i).Item("Difference") = 999
dvSortedSearchResults(ii).Item("Difference") = TrackDifference
dvSortedSearchResults(ii).Item("chkdupe") = True
End If
ii = ii + 1
End While
End Sub Else
Exit While
End If
Actually, what I might advise you to do is forget about the code you have now and use a BackgroundWorker control. Start with just creating one thread to do the work and get that up and running. The advantage is that the background worker allows you to report progress back to the main UI thread. There should be plenty of tutorials out there.
I can try to tackle/indicate some of the problems in your current code, but to be honest there is a lot wrong with it.
You have a problem where you use the same underlying object, params(2), for each thread you create, so when you modify params you thereby modify the value that all the threads see. What you need to do is create a new array for each time you want to pass an argument to a new thread.
It's also extra confusing because you are using closures Sub () checkFileDupe(params), rather than using a correct signature for checkFileDupe and using Thread.Start to pass the argument.
I'd advise you to create a Structure to hold the arguments to your thread:
Private Structure FileDupeArguments
Public StartIndex As Integer
Public TotalRecords As Integer
End Structure
Then you can create a new thread via:
Dim params As FileDupeArguments
...
thread1 = New System.Threading.Thread(AddressOf checkFileDupe)
params = New FileDupeArguments With {.StartIndex = i, .TotalRecords = totalrecords}
thread1.Start(params)
And then declaring checkFileDupe as:
Sub checkFileDupe(argObj as Object)
Dim args As FileDupeArguments = CType(argObj, FileDupeArguments)
Dim i As Integer = args.StartIndex
Dim totalRecords As Integer = args.TotalRecords
...
End Sub
The important part here is that you send a new copy of FileDupeArguments to each thread. Also, no closures are needed.
There is an issue with you accessing controls from the threads you created.
For instance,
Label2.Text = i.ToString + " of " + totalrecords.ToString
Label2.Refresh()
will not work on a background thread and will give you errors. I'd advise you to not do direct progress reports from your worker threads. Like I mentioned, a BackgroundWorker will allow you to report back progress using events.
All the code that accesses dvSortedSearchResults suffers from the same or similar problems. If you access something from multiple threads, you need to apply locks. This is already more advanced and beyond the scope of this answer to explain.

Collection was modified; enumeration operation may not execute. VB thearding

Here is my code,
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
For Each kthread As Thread In _threads
If kthread.Name = "123" Then
_threads.Remove(kthread)
kthread.Abort()
killedthreads += 1 'a integer
End If
Next
End Sub
I added the killedthreads integer at last as a check, vb executes the whole function good but at the last line it always throw the error said in title.
Not sure why, if killedthreads += 1 is not there then the error goes to kthread.Abort()
I had the same problem with C# with a different app earlier this year.
Edit,
Public Sub KillThread(kThread As Thread)
For i As Integer = (_threads.Count - 1) To 0 Step -1
If _threads.Item(i).Name = kThread.Name Then
_threads.Item(i).Abort()
_threads.RemoveAt(i)
End If
Next
End Sub
I did this code as Eminem said it. This gets in kThread from the running threads if something is not good or it has finished all its functions. But my problem is that, only the first thread that sends it gets abort and removed from list, others seem to get stuck once the first thread is aborted.
I create threads using,
Public Sub multiThreader(int As Integer, link As String)
Dim tCount As Integer = _threads.Count
If tCount >= Form1.ListView1.Items.Count Then
Else
Dim dy As Integer = DateTime.Now.Day
Dim mo As Integer = DateTime.Now.Month
Dim fileNum As String = dy.ToString() + "-" + mo.ToString() + "_" + int.ToString
botThread = New Thread(Sub() MainThread(fileNum, link, botThread, int.ToString()))
botThread.IsBackground = True
botThread.Name = String.Format("AutoBotThread{0}", fileNum)
_threads.Add(botThread)
botThread.Start()
End If
End Sub
and _threads is publicly, Public _threads As New List(Of Thread)
MainThread is a Public Sub which runs functions and gets return and send KillThread under certain conditions.
The problem is that you remove an item from an enumeration, before you finished iterating through it.
It's like trying to iterate from 0 to list.count, when the count changes from an iteration to another. As Bjørn-Roger Kringsjå said, you should do something like this:
For i As Integer = (_threads.count - 1) to 0 Step -1
If _threads.Item(i).Name = "123" Then
_threads.Item(i).Abort
_threads.RemoveAt(i)
killedthreads += 1 'a integer
End If
Next
By using Step -1 you make sure that an Index was out of range error will not occur, and make sure that your operations are fitted, and execute on the right order/item.

random number in multi threading not working

please examine my code below :
Public Class tier1
Dim rnd As New System.Random()
Function build1(ByVal dt As DataTable) As String
Try
For i = 0 To 4
For ix As Integer = 0 To till Step 4
lstrn.Add(rnd.Next(ix, ix + 4))
Next
Dim cntx As Integer = 0
For Each x As Integer In lstrn
If (i = 0) Then
If (article(x).Split(ChrW(10)).Length > 2) Then
If (article(x).Split(ChrW(10))(0).Length > 300) Then
first.Add(article(x).Split(ChrW(10))(0))
cntx = cntx + 1
If (cntx = 25) Then
Exit For
End If
End If
End If
End If
lstrn.Clear()
Next
Dim fi as String = "{"
For dx As Integer = 0 To first.Count - 2
fi = fi & w.spinl(first(dx), "light") & "|"
Next
fi = fi & "}"
Return fi
Catch ex As Exception
End Try
End Function
End Class
Now see my calling code :
Dim w As WaitCallback = New WaitCallback(AddressOf beginscn)
For var As Integer = 1 To NumericUpDown1.Value
Dim param(1) As Object
param(0) = lst
param(1) = var
ThreadPool.QueueUserWorkItem(w, param)
Next
sub
sub beginscn()
Dim scntxt As String = t1.buildtier1(dt)
end sub
Now understand what i give and what i want. Suppose i pass a datatable like this :
1,abcd,34,5
2,adfg,34,5
3,fhjrt,34,5
4,rtitk,34,5
What i want is {abcd|adfg|fhjrt|rtitk} and this sequence should be random everytime. Since i pass like 50-100 values and exit loop at 25 each output should have a different sequence of 25 strings in {|} format but it does not work like that. Everytime i get same sequence.
Can anyone explain why does it do like that and any possible solution for this problem?
Note : I have already tried shuffling datatable just before queuing it but still it does not work.
The random object is not thread safe. You could work around this by creating separate instances of the random object in each thread and use the thread ID to generate the
seed.
http://msdn.microsoft.com/en-us/library/ms683183%28VS.85%29.aspx

vb.net select random folder name

Dose anybody know how I can select an existing random directory name (C:\ drive) using vb.net and store its location in a variable.
I had to googel this one but seem to only be able to find example in relation to files, not folders
Try this out, hope this will suits your requirement,
'----------------- Global Variables
Dim xCnter = 0
Dim xRndNo = 0
Dim xSubdirectory As String
Private Sub Basement()
Dim xGenerator As System.Random = New System.Random()
xRndNo = xGenerator.Next(1, 100)
AssignRndDirectory("C:\")
msgbox(subdirectory)
End Sub
Private Sub AssignRndDirectory(xPath as string)
For Each subdirectory In Directory.GetDirectories(xPath)
if xCnter = xRndNo then Exit sub
xCnter += 1
call AssignRndDirectory(subdirectory)
Next
End Sub
[Note: This code is not tested with IDE, Tell me if anything cause errors.]
EDIT: TESTED WITH IDE
Dim xCnter = 0
Dim xRndNo = 0
Dim xSubdirectory As String
Private Sub Basement()
Dim xGenerator As System.Random = New System.Random()
xRndNo = xGenerator.Next(1, 100)
AssignRndDirectory("C:\")
MsgBox(xSubdirectory)
xCnter = 0
End Sub
Private Sub AssignRndDirectory(ByVal xPath As String)
Try
For Each Subdirectory In Directory.GetDirectories(xPath)
If xCnter = xRndNo Then Exit Sub
xSubdirectory = Subdirectory
xCnter += 1
Call AssignRndDirectory(Subdirectory)
Next
Catch ex As Exception
Exit Sub
End Try
End Sub
Just make a list of directories, and select a random item from it.
Dim rnd As New Random()
Dim path As String = "C:\"
Dim dir = New DirectoryInfo(path)
Dim subDirs = dir.GetDirectories()
Dim randomDir = subdirs(rnd.[Next](subDirs.Length))
Or, if you prefer Linq, the last line can be:
Dim randomDirectory = subdirs.Skip(rnd.[Next](subdirs.Length)).First()