Simultaneous tasks (Best way?)

2

Hello, dear friends! I'm looking for the best way to work with concurrent tasks in a graphical environment.

I have tried to use: (Thread), (Task) and (Backgroundworker). But in all I had the same problem: not being allowed to manipulate an object from another thread and if I use the invoke method the application gets very slow. In addition to this problem there is still another one: I can not get the return of a function using these tools.

I need to make a very quick application, I want it to be as fluid as possible. I would like you to share how they use the concurrent tasks ... I want to know if there are techniques or even other libraries like these ...

My focus is to run a certain function "n" times, and this function will return a message in a component such as a Listbox. I need the information to be quick.

Thank you in advance!

I took a look at how SyncLock works, in fact I had never heard of it and it even interested me, but I still have the same problem ... I'm going to post a part of my code so that you can analyze and tell me what it would be best option

A class that I gave the connection name

Public Class Conexao

    Public ip As String
    Public porta As Integer
    Public estado As Boolean

    Public Sub conectar()
        Dim cliente As New System.Net.Sockets.TcpClient

        Try
            cliente.Connect(ip, porta)
            estado = True
        Catch ex As Exception
            estado = False
        End Try

        Form1.ListBox1.Items.Add("Porta: " & porta & " Estado: " & estado)

    End Sub

End Class

And the button code

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim porta As Integer

        For index = 1 To 10
            porta = index

            Dim novaConexao = New Conexao
            novaConexao.ip = "127.0.0.1"
            novaConexao.porta = porta

            Dim thread(10) As Threading.Thread
            thread(index - 1) = New Threading.Thread(AddressOf novaConexao.conectar)
            thread(index - 1).IsBackground = True
            thread(index - 1).Start()
        Next

    End Sub

End Class

The error happens on this line:

Form1.ListBox1.Items.Add("Porta: " & porta & " Estado: " & estado)"

If I used a msgbox to show the result would work, but I need it to be Listbox , and Thread is not allowed ... any idea?

    
asked by anonymous 17.05.2015 / 01:04

2 answers

2

Only in all I had the same problem: not being allowed to manipulate an object from another thread and if I use the invoke method the application gets very slow.

You may not know the concept of critical region use of Threads . When two or more threads change a given information, the code snippet that changes this information is called a critical region .

In C #, to protect a critical region, you have to declare an object and apply it to a lock() :

protected readonly object _object = new object();
protected int meuInt = 0;

lock(_object) {
    meuInt = 1;
}

In VB.NET it's very similar:

Public meuInt As Integer = 0
Private _object As New Object 
SyncLock _object
    _object = 1
End SyncLock

My focus is to run a certain function "n" times, and this function will return a message in a component such as a Listbox. I need the information to be quick.

Using Threads tutorials you'll get this result . Just protect your critical regions properly.

For your code, try isolating critical access to ListBox as follows. It is not guaranteed to work because you are accessing a property of another class in a rather patchy way:

Public Class Conexao

    Public ip As String
    Public porta As Integer
    Public estado As Boolean
    Private _object As New Object 

    Public Sub conectar()
        Dim cliente As New System.Net.Sockets.TcpClient

        Try
            cliente.Connect(ip, porta)
            estado = True
        Catch ex As Exception
            estado = False
        End Try

        SyncLock _object
            Form1.ListBox1.Items.Add("Porta: " & porta & " Estado: " & estado)
        End SyncLock

    End Sub

End Class

The correct thing would be for the connection class to receive the reference to Listbox at boot time, avoiding access to Form1 directly, which at the time of execution may not even exist. Something like this:

    Public Sub conectar(ByRef listbox As ListBox)
        Dim cliente As New System.Net.Sockets.TcpClient

        Try
            cliente.Connect(ip, porta)
            estado = True
        Catch ex As Exception
            estado = False
        End Try

        SyncLock _object
            listbox.Items.Add("Porta: " & porta & " Estado: " & estado)
        End SyncLock

    End Sub

Usage:

Dim thread(10) As Threading.Thread
thread(index - 1) = New Threading.Thread(AddressOf novaConexao.conectar(Form1.ListBox1))
thread(index - 1).IsBackground = True
thread(index - 1).Start()

I have not tested this code.

Also, if this does not work, this article in CodeProject explains how you can modify Form components within Threads . It may be ideal for you.

    
17.05.2015 / 02:07
0

I'm sorry to report, but you'll have to use Invoke . There is no other solution.

UI controls can only be modified from the UI thread. If other threads try to modify their state, an exception occurs informing that the thread does not have permissions.

  

If I use the invoke method the application gets very slow.

This is not supposed to happen. You probably moved too much code into the Invoke call. Try to execute Invoke with only this line: Form1.ListBox1.Items.Add("Porta: " & porta & " Estado: " & estado) . If the code is still slow, the problem is elsewhere in the code.

EDIT

Another equivalent solution (and that should be used after .NET 4.5) is the use of async / await.

I do not know the VB.NET syntax, but in C # it would look like this:

private async void Button1_Click(object sender, EventArgs args)
{
    bool estado = false;
    await Task.Run(() => {

        //conectar ao client TCP
        estado = true;
    });

    Form1.ListBox1.Items.Add("Porta: " + porta + " Estado: " + estado);
}

Task.Run defers the job of connecting the TCP client to a threadpool thread, and await waits asynchronously for the task to complete - that is, while the threadpoolpool connects to the client, the UI thread is free to handle other events.

The rest of the method code will be executed again in the UI thread as soon as the task completes.

    
18.05.2015 / 02:44