开发者

Synchronizing sub-thread with main thread - not so obvious problem

开发者 https://www.devze.com 2023-01-10 05:17 出处:网络
To be honest, I\'m a little bit lame when it comes to threading ;) So开发者_StackOverflow社区 I\'m asking for a little help.

To be honest, I'm a little bit lame when it comes to threading ;) So开发者_StackOverflow社区 I'm asking for a little help.

Let's assume, we have some kind of control on which we can draw some charts. There's also a method that draws a chart on this control. The problem is that the charting method has access only to one of the fields of the control and we need to refresh the control when the chart is ready.

So let's assume our control looks like that:

class ChartingControl : System.Windows.Forms.Control
{
    public Canvas canvas;
    public void Refresh();
    /*
     ... other fields/methods
    */
}

where Canvas is a class used to draw the image (something like Graphics).

The charting method has access only to the canvas object (we cannot change it), so it looks like that:

public static void DrawChart(canvas)
{ /* draw */ } 

This method can be called from a separate thread, background worker etc... And I need to synchronize it with the main thread and call Refresh() when the chart is ready.

Right now when the chart is ready, I set a flag on canvas object

public static void DrawChart(canvas)
{ /* draw */ 
  canvas.Tag = true; // chart is ready
}

And I have a background worker running inside of the charting control and listening if the canvas.Tag field has changed and if so, it calls Refresh()

But it seems that my method is a little bit rought, easy-to-fail etc... Is there any better method to improve it?

Limitations:

- we cannot modify Canvas class. The only thing we can use is the Tag field (of type object

- we can modify ChartingControl class and drawing method.

- There can be many charting controls

- We have no control over how DrawChart is called. It can be called in a separate thread, or not. It is called elsewhere. All we can do is to create the control and the DrawChart method and try to comunicate them somehow

Solution

OK, I solved it this way: in ChartingControl I created a ManualResetEvent manualReset and a background worker.

Bacground worker waits for the manualReset:

    void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
            manualReset.WaitOne(); // Wait for a chart to be ready
    }

and in the end calls Reset() method

void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        Refresh();
    }

I pass the manualReset object inside canvas.Tag and inside drawing method, when the chart is ready I call manualReset.Set(); to pass the signal that chart is ready.


OK, I solved it this way: in ChartingControl I created a ManualResetEvent manualReset and a background worker.

Bacground worker waits for the manualReset:

    void backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {
            manualReset.WaitOne(); // Wait for a chart to be ready
    }

and in the end calls Reset() method

void backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        Refresh();
    }

I pass the manualReset object inside canvas.Tag and inside drawing method, when the chart is ready I call manualReset.Set(); to pass the signal that chart is ready.


Supposing you deal with synchronization of access to the Canvas object, I will just recommend that you do
myChartingControl.Invoke(new Action(myChartingControl.Refresh));
from another thread that draws the chart


BackgroundWorker will help you

  void StartDrawChart (){

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        bw.RunWorkerAsync()
  }


   void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
   {
        this.Refresh();
   }

   void bw_DoWork(object sender, DoWorkEventArgs e)
   {
        DrawChart(this.canvas);
   }
0

精彩评论

暂无评论...
验证码 换一张
取 消