【问题标题】:Control 'ZedGraphControl' accessed from a thread other than the thread it was created on控件“ZedGraphControl”从创建它的线程以外的线程访问
【发布时间】:2015-11-10 11:37:58
【问题描述】:

我正在使用 ZedGraph 库,但在网站而不是 Web 表单应用程序上。快速介绍 - 应用从数据库中获取数据,生成图表,将其保存为图像,然后将图像显示在网页上。

我有一个 GraphController 类,基本上是这样的:

public class GraphController {

    private static GraphController instance;
    private static ZedGraph.ZedGraphControl graph;
    protected GraphController() { }

    public static GraphController Instance {
        get {
            if (instance == null){
                instance = new GraphController();
            }
            return instance;
        }
    }

    public string GenerateGraph(Dictionary<DateTime, float> graphData, DataRow details, string graphType) {
        if ((graph == null) || (graph.IsDisposed == false)) {
            graph = new ZedGraph.ZedGraphControl();
        }
        graph.GraphPane.Title.IsVisible = false;
        // function calls to generate graph. Graph object is referenced in these.
        return SaveGraphAsImage(0000, graphType);
    }

    private void AddGridLines() {
        // example of graph reference
        graph.GraphPane.XAxis.MajorGrid.IsVisible = true;
    }

    private string SaveGraphAsImage(string paramId, string graphType) {
        // Should deal with save location here 
        string location = HttpRuntime.AppDomainAppPath + "Graphs\\" + DateTime.Now.ToString("dd-MM-yyyy");
        string filename = DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss-") + graphType + "-" + paramId + ".png";

        if(System.IO.Directory.Exists(location) == false){
            System.IO.Directory.CreateDirectory(location);
        }
        graph.Refresh();

        try {
            using (graph) {
                string outputFileName = location + "\\" + filename;

                if (File.Exists(outputFileName) == false) {
                    Bitmap image = graph.GraphPane.GetImage(960, 660, 180);
                    image.Save(outputFileName, ImageFormat.Png);
                    image.Dispose();
                }
            }
            graph = null; // double check that it is removed.
            return "../Graphs/" + DateTime.Now.ToString("dd-MM-yyyy") + "/" + filename;
        }
        catch (Exception ex) {
            log("An error occured generating a graph. \n\n Error message: \n " + ex.Message + " \n\n Stack trace: \n " + ex.StackTrace);
            graph = null;
            return "#";
        }
    }
}

我已尽可能减少它,但它应该显示 ZedGraph 对象是如何创建、使用和删除的。

我已经尝试了一些内存增强,尽可能删除图形对象,并尝试using(){} 进程希望自动删除它,但欢迎进一步的建议。

我的目标是改进内存管理并减少这些错误。运行本地性能测试,我得到不少Control 'ZedGraphControl' accessed from a thread other than the thread it was created on. 错误。我对线程比较陌生,所以我不确定a)它是否是这里需要的东西,或者b)可以做一些事情来禁用这种可能性,或者更好地管理图形对象以确保它总是在同一个线程中?

编辑:这个GraphController首先是从一个.aspx.cs页面调用的:GraphController.GraphController.Instance.GenerateGraph(data, details, "graph-type");

第二次编辑:我重新编写了代码,使 ZedGraphControl 不再是 private static,而是在 GenerateGraph 中创建,然后在必要时传递。在 60 秒内对多达 1,000 名用户进行测试似乎已经消除了跨线程问题 - 这听起来可能吗?

【问题讨论】:

  • 这听起来可能吗? - 是的,它向您展示了为什么在 Web 应用程序中避免使用static
  • 谢谢@HenkHolterman - 听起来像是我需要阅读的内容!另外 - 您是否建议在这种情况下也更改/不使用实例进程?
  • "建议不要使用Instance进程" 是的,看起来无害,但也没有任何收获。保持简单,保持范围和生命周期尽可能小。

标签: c# asp.net multithreading zedgraph


【解决方案1】:

这里的问题是static 变量的使用。正如 Henk Holterman 在 cmets 中指出的那样,只要应用程序进程处于活动状态,静态变量就会保持活动状态,并且与任何/所有用户请求分开。因此,将ZedGraph 对象作为static 变量并不意味着它可能仍可用于多个请求,而无需正确清除、运行到内存和跨线程问题。

解决方案是在第一个 GenerateGraph 函数中声明 ZedGraph 实例,然后将相同的对象传递给使用它的每个其他函数。这样可以确保在整个进程中访问的是同一个线程中的同一个对象。

【讨论】:

    猜你喜欢
    • 2014-09-19
    • 1970-01-01
    • 2011-01-15
    • 2016-05-21
    • 2016-06-11
    • 2015-05-14
    • 1970-01-01
    相关资源
    最近更新 更多