Search code examples
c#socketsnetwork-programmingtcp

Why can I not recursively call a Worker_DoWork function?


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.


Solution

  • 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