Simultaneous tasks (Best way?)

Asked

Viewed 314 times

2

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

I have tried using: (Thread), (Task) and (Backgroundworker). But in all of them I had the same problem: not having permission to manipulate an object from another thread and if I use the invoke method the application is very slow. In addition to this problem there is another: I cannot receive the return of a function using these tools.

I need to do a very fast application, I want it to be as fluid as possible. I would like you to share how you use simultaneous tasks... I want to know if there are techniques or even other libraries like these...

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

Thank you in advance!


I took a look at how Synclock works, in fact I had never heard of it and even interested myself, but I still have the same problem... I’ll post a piece of my code so you can analyze and tell me which would be the best option

A class 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 one msgbox to show the result would work, but I need it to be on Listbox, and the Thread is not allowed... any idea?

2 answers

2

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

Maybe you don’t know the concept of critical region inherent to the use of Threads. When two or more Threads change a certain information, the code snippet that changes that information is called critical region.

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

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

lock(_object) {
    meuInt = 1;
}

In VB.NET is very similar:

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

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

Using the Threads tutorials you will get this result. Just protect your critical regions properly.


In the case of your code, try isolating access to the ListBox as follows. It is not guaranteed to work because you are accessing a property of another class in a very irregular 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 most correct would be the connection class receiving the reference to the Listbox at the time of initialization, 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

Use:

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.

Still, if it doesn’t work this way, there is this article in Codeproject that explains how you can modify Form components within Threads. Might be just the thing for you.

  • This does not solve the cross-thread permission problem.

  • I think it’s now clear why I use Synclock Mas and as for the permissions problem, what options do I have ?

  • I don’t know exactly what error you are having, but in its place, I would pass to the function "worker" the reference to the list you want to update on screen.

  • Could you send me a little example of how to pass the listbox reference ?

  • @Wesleysilva I edited the answer.

0

I’m sorry to inform you, but you’re gonna have to use Invoke. There’s no other way.

UI controls can only be modified from the UI thread. If other threads try to modify its state, there is an exception stating that the thread does not have permissions.

if I use the invoke method the application gets too slow.

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


EDIT

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

I don’t know the syntax of VB.NET, but in c# it would be 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 defer the work of connecting the TCP client to a threadpool thread, and await waits asynchronously for the task to complete - that is, while the threadpool thread connects to the client, the UI thread is free to handle other events.

The rest of the method code will run again in the UI thread once the task is completed.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.