Aakar
Aakar

Reputation: 87

How does the BackgroundWorker work exactly?

I have written this code for a Message Receiving class that uses a backgroundworker to check for new files in a directory (the files are SMS messages received from users that are updating continuously). If the directory is not empty, I send an acknowledgement message to every new SMS and start the worker again.

 public MessageReceiving()
    {
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);           
    }
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {   
        if(e.Result == true)
        { 
        SendAcknowledgement();
        if(!bw.IsBusy)
            bw.RunWorkerAsync();
        }
    }

void bw_DoWork(object sender, DoWorkEventArgs e)
    {
       bool flag = false;
        while (flag.Equals(false))
        {
            string path = @"C:\SMS";
            if (Directory.GetFiles(path).Length > 0)
            {
                e.Result = true;
                flag = true;
            }
            else
            {
                e.Result = false;
            }
        }

    }

I initialize the worker from the main thread once -

MessageReceiving mr = new MessageReceiving();
mr.bw.RunWorkerAsync();

I did all this to allow me to send messages synchronously to users - As soon as a user send an SMS, I send him an ACK. The problem is that the user is getting multiple ACKs even on sending one SMS - why is this happening? I have thought of every possibility, but to no avail!

Upvotes: 1

Views: 942

Answers (2)

Henk Holterman
Henk Holterman

Reputation: 273854

It depends on code not shown.

You need at most 1 thread scanning the files. Then somewhere during the processing you have to remove or rename the files. In your case this should happen in SendAcknowledgement, and the Bgw should not be restarted before it all replies have been sent.

It would be better to use a rename the files early and push them in a queue. Or process them directly after finding a file inside DoWork. SendAcknowledgement(fileName) looks more logical.

Currently your SendAcknowledgement() runs in the main thread, that may not be what you want.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1504122

Consider what happens when this starts:

  • You start running bw_DoWork
  • That then tight-loops (not a good idea to start with) until it finds a file
  • The background worker completes, and you send an acknowledgement
  • You then immediately run the background worker again... which will find the file again unless you've deleted the file during SendAcknowledgement. Have you?

I suspect what you really want instead of any of this is a FileSystemWatcher by the way. Also note that just because a file is present doesn't mean that it's finished being written to yet, or that you can read it.

Additionally, your tight loop can be made a lot simpler:

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    string path = @"C:\SMS";
    while (!e.Result)
    {
        e.Result = Directory.GetFiles(path).Any();
    }
}

and I would likewise change

if (e.Result == true)

to

if (e.Result)

(Assuming e.Result is typed as a bool; if it's not, your current code has other problems.)

Upvotes: 2

Related Questions