Damien
Damien

Reputation: 273

In C#; what is the most efficent way to check for changes from a background thread?

I create a thread for each of my network communications and they add to a list responses whenever they hear back from a client. I'm starting up the task below at execution to see if any communications come in. It displays the most recent one on screen.

Task task = new Task(
(() =>
 {
    int i = 0;
    while (true)
    {
        if (responses.Count > i){
            Debug.WriteLine(responses[i]);
            int index = Form.ActiveForm.Controls.IndexOfKey("responseBox");
            Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Visible = true));
            Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Text = responses[i]));
            i++;
        }
    }
 }));
task.Start();

My question is; is there a better way for me to do this? It seems wrong to me to have the task constantly working for something that doesn't happen very often.

Edit: I'm very new to C#, so if there's something obvious please don't hesitate to point it out.

Update:

As per the nice tutorial from MS that sidewinder linked I added a simple event to the Add function of List. as So:

public delegate void ChangedEventHandler(object sender, EventArgs e);

public class listWithChanges<T> : List<T> 
{
    public event ChangedEventHandler Changed;

    protected virtual void OnChanged(EventArgs e)
    {
        if (Changed != null)
            Changed(this, e);
    }

    public new void Add (T item)
    {
        base.Add(item);
        OnChanged(EventArgs.Empty);
    }
}

and added to my output with a delegate

responses.Changed += ((o, e) => {
                                int index = Form.ActiveForm.Controls.IndexOfKey("responseBox");
                                Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Visible = true));
                                Form.ActiveForm.Invoke((MethodInvoker) (() => Form.ActiveForm.Controls[index].Text = responses[responses.Count - 1]));
                              });

Upvotes: 5

Views: 138

Answers (2)

Mike Nakis
Mike Nakis

Reputation: 61969

If you don't want to have to go through great restructuring of your code, you can use a blocking queue for your responses collection, so that your reading thread blocks while waiting for an item to appear in the queue.

Waiting for something to appear in a blocking queue consumes zero CPU. (Technically non-zero, but nonetheless unnoticeable.)

A quick search yields this: MSDN - BlockingCollection Class

Upvotes: 2

Genos
Genos

Reputation: 421

Events would be a nice solution.

An event is an implementation of the Observer pattern, in which the source (the network communications) warn it's observers(whoever calls the task in your example) that something happened.

It's a lot more efficient since it doesn't waste CPU usage in an infinite loop, the method only executes when a client responds.

C# has a great support for events, consider reading the MS Tutorial(originally posted by Sidewinder94).

Upvotes: 4

Related Questions