random number in multi threading not working - vb.net

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

Related

Splitting string every 100 characters not working

I am having a problem where I just can't seem to get it to split or even display the message. The message variable is predefined in another part of my code and I have debugged to make sure that the value comes through. I am trying to get it so that every 100 characters it goes onto a new line and with every message it also goes onto a new line.
y = y - 13
messagearray.AddRange(Message.Split(ChrW(100)))
Dim k = messagearray.Count - 1
Dim messagefin As String
messagefin = ""
While k > -1
messagefin = messagefin + vbCrLf + messagearray(k)
k = k - 1
End While
k = 0
Label1.Text = Label1.Text & vbCrLf & messagefin
Label1.Location = New Point(5, 398 + y)
You can use regular expression. It will create the array of strings where every string contains 100 characters. If the amount of remained characters is less than 100, it will match all of them.
Dim input = New String("A", 310)
Dim mc = Regex.Matches(input, ".{1,100}")
For Each m As Match In mc
'// Do something
MsgBox(m.Value)
Next
You can use LINQ to do that.
When you do a Select you can get the index of the item by including a second parameter. Then group the characters by that index divided by the line length so, the first character has index 0, and 0 \ 100 = 0, all the way up to the hundredth char which has index 99: 99 \ 100 = 0. The next hundred chars have 100 \ 100 = 1 to 199 \ 100 = 1, and so on (\ is the integer division operator in VB.NET).
Dim message = New String("A"c, 100)
message &= New String("B"c, 100)
message &= New String("C"c, 99)
Dim lineLength = 100
Dim q = message.Select(Function(c, i) New With {.Char = c, .Idx = i}).
GroupBy(Function(a) a.Idx \ lineLength).
Select(Function(b) String.Join("", b.Select(Function(d) d.Char)))
TextBox1.AppendText(vbCrLf & String.Join(vbCrLf, q))
It is easy to see how to change the line length because it is in a variable with a meaningful name, for example I set it to 50 to get the output
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
You can use String.SubString to do that. Like this
Dim Message As String = "your message here"
Dim MessageList As New List (Of String)
For i As Integer = 0 To Message.Length Step 100
If (Message.Length < i + 100) Then
MessageList.Add(Message.SubString (i, Message.Length - i)
Exit For
Else
MessageList.Add(Message.SubString (i, 100))
End If
Next
Dim k = MessageList.Count - 1
...
Here is what your code produced with a bit of clean up. I ignored the new position of the label.
Private Sub OpCode()
Dim messagearray As New List(Of String) 'I guessed that messagearray was a List(Of T)
messagearray.AddRange(Message.Split(ChrW(100))) 'ChrW(100) is lowercase d
Dim k = messagearray.Count - 1
Dim messagefin As String
messagefin = ""
While k > -1
messagefin = messagefin + vbCrLf + messagearray(k)
k = k - 1
End While
k = 0 'Why reset k? It falls out of scope at End Sub
Label1.Text = Label1.Text & vbCrLf & messagefin
End Sub
I am not sure why you think that splitting a string by lowercase d would have anything to do with getting 100 characters. As you can see the code reversed the order of the list items. It also added a blank line between the existing text in the label (In this case Label1) and the new text.
To accomplish your goal, I first created a List(Of String) to store the chunks. The For loop starts at the beginning of the input string and keeps going to the end increasing by 10 on each iteration.
To avoid an index out of range which would happen at the end. Say, we only had 6 characters left from start index. If we tried to retrieve 10 characters we would have an index out of range.
At the end we join the elements of the string with the separated of new line.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
BreakInto10CharacterChunks("The quick brown fox jumped over the lazy dogs.")
End Sub
Private Sub BreakInto10CharacterChunks(input As String)
Dim output As New List(Of String)
Dim chunk As String
For StartIndex = 0 To input.Length Step 10
If StartIndex + 10 > input.Length Then
chunk = input.Substring(StartIndex, input.Length - StartIndex)
Else
chunk = input.Substring(StartIndex, 10)
End If
output.Add(chunk)
Next
Label1.Text &= vbCrLf & String.Join(vbCrLf, output)
End Sub
Be sure to look up String.SubString and String.Join to fully understand how these methods work.
https://learn.microsoft.com/en-us/dotnet/api/system.string.substring?view=netframework-4.8
and https://learn.microsoft.com/en-us/dotnet/api/system.string.join?view=netframework-4.8

multiple threading in nested loop in vb

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

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.

VB "Index was out of range, must be non-negative and less than the size of the collection." When trying to generate a random number more than once

So I'm trying to generate a random number on button click. Now this number needs to be between two numbers that are inside my text file with various other things all separated by the "|" symbol. The number is then put into the text of a textbox which is being created after i run the form. I can get everything to work perfectly once, but as soon as i try to generate a different random number it gives me the error: "Index was out of range, must be non-negative and less than the size of the collection." Here is the main code as well as the block that generates the textbox after loading the form. As well as the contents of my text file.
Private Sub generate()
Dim newrandom As New Random
Try
Using sr As New StreamReader(itemfile) 'Create a stream reader object for the file
'While we have lines to read in
Do Until sr.EndOfStream
Dim line As String
line = sr.ReadLine() 'Read a line out one at a time
Dim tmp()
tmp = Split(line, "|")
rows(lineNum).buybutton.Text = tmp(1)
rows(lineNum).buyprice.Text = newrandom.Next(tmp(2), tmp(3)) 'Generate the random number between two values
rows(lineNum).amount.Text = tmp(4)
rows(lineNum).sellprice.Text = tmp(5)
rows(lineNum).sellbutton.Text = tmp(1)
lineNum += 1
If sr.EndOfStream = True Then
sr.Close()
End If
Loop
End Using
Catch x As Exception ' Report any errors in reading the line of code
Dim errMsg As String = "Problems: " & x.Message
MsgBox(errMsg)
End Try
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
rows = New List(Of duplicate)
For dupnum = 0 To 11
'There are about 5 more of these above this one but they all have set values, this is the only troublesome one
Dim buyprice As System.Windows.Forms.TextBox
buyprice = New System.Windows.Forms.TextBox
buyprice.Width = textbox1.Width
buyprice.Height = textbox1.Height
buyprice.Left = textbox1.Left
buyprice.Top = textbox1.Top + 30 * dupnum
buyprice.Name = "buypricetxt" + Str(dupnum)
Me.Controls.Add(buyprice)
pair = New itemrow
pair.sellbutton = sellbutton
pair.amount = amounttxt
pair.sellprice = sellpricetxt
pair.buybutton = buybutton
pair.buyprice = buypricetxt
rows.Add(pair)
next
end sub
'textfile contents
0|Iron Sword|10|30|0|0
1|Steel Sword|20|40|0|0
2|Iron Shield|15|35|0|0
3|Steel Shield|30|50|0|0
4|Bread|5|10|0|0
5|Cloak|15|30|0|0
6|Tent|40|80|0|0
7|Leather Armour|50|70|0|0
8|Horse|100|200|0|0
9|Saddle|50|75|0|0
10|Opium|200|500|0|0
11|House|1000|5000|0|0
Not sure what else to add, if you know whats wrong please help :/ thanks
Add the following two lines to the start of generate():
Private Sub generate()
Dim lineNum
lineNum = 0
This ensures that you don't point to a value of lineNum outside of the collection.
I usually consider it a good idea to add
Option Explicit
to my code - it forces me to declare my variables, and then I think about their initialization more carefully. It helps me consider their scope, too.
Try this little modification.
I took your original Sub and changed a little bit take a try and let us know if it solve the issue
Private Sub generate()
Dim line As String
Dim lineNum As Integer = 0
Dim rn As New Random(Now.Millisecond)
Try
Using sr As New StreamReader(_path) 'Create a stream reader object for the file
'While we have lines to read in
While sr.Peek > 0
line = sr.ReadLine() 'Read a line out one at a time
If Not String.IsNullOrEmpty(line) And Not String.IsNullOrWhiteSpace(line) Then
Dim tmp()
tmp = Split(line, "|")
rows(lineNum).buybutton.Text = tmp(1)
rows(lineNum).buyprice.Text = rn.Next(CInt(tmp(2)), CInt(tmp(3))) 'Generate the random number between two values
rows(lineNum).amount.Text = tmp(4)
rows(lineNum).sellprice.Text = tmp(5)
rows(lineNum).sellbutton.Text = tmp(1)
lineNum += 1
End If
End While
End Using
Catch x As Exception ' Report any errors in reading the line of code
Dim errMsg As String = "Problems: " & x.Message
MsgBox(errMsg)
End Try
End Sub

VB, how to solve this error

I have some problem in my code :
For i = 0 To Split(awal, vbCrLf).Length - 1
For j = 0 To Split(hasil(i), " ").Length - 1
hasil1(j) = hasil(i).Split(" ")
Next j
Next i
it comes with error :
"Value of type '1-dimensional array of String' cannot be converted to
'String' " in the " hasil1(j) = hasil(i).Split(" ") " section.
can anyone explain to me how to solve this, please?
It is not clear how you initialize your hasil array,
however, you could simplify your code using a List(Of String) in this way
Dim hasil() as String = New String() {"abcd 123","efgh 11","ijkl"}
Dim hasil1 as List(Of String) = New List(Of String)()
For i = 0 To hasil.Length - 1
hasil1.AddRange(hasil(i).Split(" "))
Next i
You can allways convert it back to a string array with:
Dim s() as String = hasil1.ToArray()
You problem is that you are trying to add an Array to a String Array.
The Split() function returns an Array and this is causing the error.
If your intention is to get an Array of Arrays, make that variables that way, if not, what was the purpose on using Split(" ") on that line?
Edit:
Based on you comment:
You will have to loop once more for this to be complete:
Dim it As Integer
Dim tmp() As String
it = 0
For i = 0 To Split(awal, vbCrLf).Length - 1
For j = 0 To Split(hasil(i), " ").Length - 1
tmp = hasil(i).Split(" ")
For k = 0 To tmp.Length - 1
hasil1(it) = tmp(k)
it += 1
Next
Next j
Next i
My skills in VB.Net are rusted and I'm not in my dev machine, so try this and let me know if something doesn't work.