c#: using threads in a "windows Forms" project

Asked

Viewed 186 times

4

In my application I have several "subprocesses". They all emit information in which they are displayed in the Form.

I used System.Windows.Forms.Timer:

Class x {
    public Timer timer {get; set;}

    public void f()
    {
        timer = new Timer();
        timer.Tick += new EventHandler(this.tick);
        timer.Enabled = false;
        timer.Interval = 1000;
        timer.Start();
    }

    private async void tick(object sender, EventArgs e)
    {
        this.status = ProcessoStatus.TRABALHANDO;
        this.timer.Stop();

        await Task.Run(() => this.processo());

        this.timer.Start();
        this.status = ProcessoStatus.OCIOSO;
    }
}

One of these subprocesses checks a web service for updated data. But for that I need all other lawsuits to stop.

// main thread
Class Y
{
    public void a()
    {
        X obj1 = new X();
        X obj2 = new X();
        obj1.f();
        obj2.f();
    }

    public sync()
    {
        obj1.timer.Enabled = false;
        while (obj1.status != ProcessoStatus.OCIOSO)
        {
            // faz nada no loop, apenas aguarda o método tick terminar
        }

        obj2.timer.Enabled = false;
        while (obj2.status != ProcessoStatus.OCIOSO)
        { }

        // pega os dados novos do webservice
    }
 }

The problem is that while in many cases hangs the main thread causing the "status" to never be "idle".

Any suggestions to improve this?

1 answer

1


The problem is that the tick of System.Windows.Forms.Timer runs in the thread UI - and the thread UI is waiting for the tick to end. That is, a deadlock occurs.

The solution is to make the thread UI wait asynchronously. There are several ways to do this, one of them would be to make each instance of x expose a Task representing the state of the proceedings (and thus no longer necessary ownership status.

class TimedProcess {
    public Timer Timer {get; private set;}

    public Task Completed { get; private set; }

    public TimedProcess()
    {
        timer = new Timer();
        timer.Tick += new EventHandler(this.Tick);
        timer.Enabled = false;
        timer.Interval = 1000;
        timer.Start();
    }

    private async void Tick(object sender, EventArgs e)
    {
        this.timer.Stop();

        Completed = Task.Run(() => this.processo());

        await Completed;
        timer.Start();
    }
}


// UI Thread
public async Task Sync()
{
    obj1.Timer.Enabled = false;
    await obj1.Completed;

    obj2.timer.Enabled = false;
    await obj2.Completed;

    // pega os dados novos do webservice
}

Thus, the method Sync will release the thread UI until the tick is over.

Note that I made some changes:

  • The names of methods in C# are written in PascalCasing (not in camelCasing)
  • I moved the creation of the timer to the constructor
  • I renamed the class x for TimedProcess, to have a more meaningful name.

Browser other questions tagged

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