将子线程与主线程同步 - 不是那么明显的问题

时间:2010-08-03 13:49:31

标签: c# multithreading

老实说,我在线程方面有点蹩脚;)所以我要求一点帮助。

让我们假设,我们可以通过某种控制来绘制一些图表。还有一种方法可以在此控件上绘制图表。问题是图表方法只能访问控件的一个字段,我们需要在图表准备好时刷新控件。

所以让我们假设我们的控制看起来像这样:

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

其中Canvas是用于绘制图像的类(类似图形) 图表方法只能访问canvas对象(我们无法更改它),所以看起来像这样:

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

可以从单独的线程,后台工作程序等调用此方法......我需要将其与主线程同步,并在图表准备就绪时调用Refresh()

现在图表准备就绪后,我在画布对象上设置了一个标志

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

我有一个后台工作人员在图表控件内部运行并在canvas.Tag字段发生变化时进行监听,如果是,则调用Refresh()

但似乎我的方法有点挣扎,容易失败等......有没有更好的方法来改进它?

限制:
- 我们无法修改Canvas课程。我们唯一可以使用的是Tag字段(类型为object) - 我们可以修改ChartingControl类和绘图方法 - 可以有许多图表控制 - 我们无法控制DrawChart的调用方式。它可以在单独的线程中调用,也可以不调用。它被称为其他地方。我们所能做的就是创建控件和DrawChart方法并尝试以某种方式将它们联系起来

解决方案
好的,我这样解决了:在ChartingControl我创建了一个ManualResetEvent manualReset和一个后台工作者。

Bacground工作人员等待manualReset

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

并最终调用Reset()方法

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

我在manualReset内传递canvas.Tag对象,在绘图方法中,当图表准备就绪时,我调用manualReset.Set();来传递图表准备就绪的信号。

3 个答案:

答案 0 :(得分:1)

好的,我这样解决了:在ChartingControl我创建了一个ManualResetEvent manualReset和一个后台工作者。

Bacground工作人员等待manualReset

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

并最终调用Reset()方法

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

我在manualReset内传递canvas.Tag对象,在绘图方法中,当图表准备就绪时,我调用manualReset.Set();来传递图表准备就绪的信号。

答案 1 :(得分:0)

假设您处理对Canvas对象的访问同步,我建议您执行 myChartingControl.Invoke(new Action(myChartingControl.Refresh));
来自另一个绘制图表的线程

答案 2 :(得分:0)

BackgroundWorker会帮助您

  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);
   }