1

I have a tcp server and client in c# using Sytem.Net.Sockets. My worker function is as following

   private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        byte[] buffer = new byte[1];
        socket.Receive(buffer);
        chatTextBox.Text = buffer[0].ToString();        
    }

I'm calling this after the server is created, as soon as it receives a message from the client it writes it on the screen and stops. My issue is I want it at the end to call itself again so it waits for another message to display. If I just add worker.RunWorkerAsync(); at the bottom it doesn't work, however if I just call it from another button it works and receives and writes the message.

1 Answers1

1

The BackgroundWorker "wraps" around a Thread and helps you with all the plumbing. It is a horribly dated approach to Multitasking taht you should not use in producive code anymore. However it is also the best "Training Wheels" for Multitasking I know off.

Your fundamental approach is flawed. The BGW not allowing that is really just it helping you learn the things you need to learn. A list of mistakes in your code:

  • you are accessing a GUI element directly in DoWork. Do not do that. Only write the UI in ReportProgress and RunWorker completed Events. This is a general Multithreading rule, that is helped by teh BGW's design.
  • you are trying to restart the thread, before it has finished. If you wanted to restart it, RunWorkerCompleted would be the right place
  • however more sensible would be for the core of the BackgroundWorker to be a semi-infinite loop. Something that runs until canceled. Normally handing out inforamtion with reporting is not a good idea, but in this case it is the best idea I have.

The only other thing I can give you, is my old BGW example code:

#region Primenumbers
private void btnPrimStart_Click(object sender, EventArgs e)
{
    if (!bgwPrim.IsBusy)
    {
        //Prepare ProgressBar and Textbox
        int temp = (int)nudPrim.Value;
        pgbPrim.Maximum = temp;
        tbPrim.Text = "";

        //Start processing
        bgwPrim.RunWorkerAsync(temp);
    }
}

private void btnPrimCancel_Click(object sender, EventArgs e)
{
    if (bgwPrim.IsBusy)
    {
        bgwPrim.CancelAsync();
    }
}

private void bgwPrim_DoWork(object sender, DoWorkEventArgs e)
{
    int highestToCheck = (int)e.Argument;
    //Get a reference to the BackgroundWorker running this code
    //for Progress Updates and Cancelation checking
    BackgroundWorker thisWorker = (BackgroundWorker)sender;

    //Create the list that stores the results and is returned by DoWork
    List<int> Primes = new List<int>();


    //Check all uneven numbers between 1 and whatever the user choose as upper limit
    for(int PrimeCandidate=1; PrimeCandidate < highestToCheck; PrimeCandidate+=2)
    {
        //Report progress
        thisWorker.ReportProgress(PrimeCandidate);
        bool isNoPrime = false;

        //Check if the Cancelation was requested during the last loop
        if (thisWorker.CancellationPending)
        {
            //Tell the Backgroundworker you are canceling and exit the for-loop
            e.Cancel = true;
            break;
        }

        //Determin if this is a Prime Number
        for (int j = 3; j < PrimeCandidate && !isNoPrime; j += 2)
        {
            if (PrimeCandidate % j == 0)
                isNoPrime = true;
        }

        if (!isNoPrime)
            Primes.Add(PrimeCandidate);
    }

    //Tell the progress bar you are finished
    thisWorker.ReportProgress(highestToCheck);

    //Save Return Value
    e.Result = Primes.ToArray();
}

private void bgwPrim_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    pgbPrim.Value = e.ProgressPercentage;
}

private void bgwPrim_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    pgbPrim.Value = pgbPrim.Maximum;
    this.Refresh();

    if (!e.Cancelled && e.Error == null)
    {
        //Show the Result
        int[] Primes = (int[])e.Result;

        StringBuilder sbOutput = new StringBuilder();

        foreach (int Prim in Primes)
        {
            sbOutput.Append(Prim.ToString() + Environment.NewLine);
        }

        tbPrim.Text = sbOutput.ToString();
    }
    else 
    {
        tbPrim.Text = "Operation canceled by user or Exception";
    }
}
#endregion
Christopher
  • 9,634
  • 2
  • 17
  • 31
  • The second suggestion of adding a RunWorkerComplete was exactly what I wanted! I know it is really bad coding but I just wanted to understand how exactly the process worked and this helped. You said that Background worker is an outdated thing, what should I use instead of it to run my multitasking? Any links always appreciated! Just making a simple client/server tcp chat application! – Rainflow901 May 11 '20 at 00:26
  • @Rainflow901 For beginners, BGW is about ideal. It basically forces you into the proper patterns, via it's limitations and rules. The current "thing" is async mechanic. A way to do multitasking without resorting all the way to threads. Generally Thread should only be used in two cases: a) the work is CPU bound. But those cases are rare. b) Large scale servers. Those go all the way to ThreadPools. The isolation that Threads bring can help a lot. – Christopher May 11 '20 at 01:39