0

我有一个程序,我有一个线程计时器来更新来自数据服务器的时间。但是,我注意到计时器运行了几次,然后停止调用。我尝试将线程定时器代码复制到一个新程序上,它运行良好,所以我知道定时器代码一定会干扰程序的其余部分,但我不知道在哪里,有人可以帮我吗?

该程序非常大,可以在这里发布所有内容,我尝试在这里发布所有相关部分。

public partial class HistoricalDownload : Form
{
    static int column = 2;
    static int row = 100;

    string timeFmt = "yyyy/MM/dd HH:mm:ss.fff";

    ZenFire.Connection zf;
    ZenFire.Connection.TickEventHandler tick;
    ZenFire.IProduct product = null;

    System.Windows.Forms.TextBox[,] textbox = new System.Windows.Forms.TextBox[column, row];
    DisplayTimer displayTimer = new DisplayTimer();
    memoryStreamClass msc = new memoryStreamClass();
    Dictionary<string, int> dictionarySymbol = new Dictionary<String, int>();
    delegate void StringParameterDelegate(int j, string value);

    public HistoricalDownload(ZenFire.Connection z)
    {
        InitializeComponent();

        int month = 0;
        int year = 0;

        string symbol;
        string exchange;
        string finalSymbol;

        string[] lineSplit;

        zf = z;
        tick = new ZenFire.Connection.TickEventHandler(zf_TickEvent);
        zf.TickEvent += tick;

                //set the array for name and update time 

        for (int k = 0; k < column; k++)
        {
            for (int j = 0; j < row; j++)
            {
                textbox[k, j] = new System.Windows.Forms.TextBox();
                textbox[k, j].Size = new Size(140, 18);
                textbox[k, j].Name = "textbox_" + k + "_" + j;

                if (j >= 50)
                {
                    textbox[k, j].Location = new System.Drawing.Point((k * 140) + 400, ((j - 50) * 18) + 30);
                }
                else
                {
                    textbox[k, j].Location = new System.Drawing.Point((k * 140) + 20, (j * 18) + 30);
                }

                textbox[k, j].Visible = true;
                Controls.Add(textbox[k, j]);
            }
        }

                //load the config file and subscribe the symbol

                    ....

                ///////////////////////////////////////

        System.Threading.TimerCallback displayCallback = new System.Threading.TimerCallback(timeDisplay);
        System.Threading.Timer displayTimerThread = new System.Threading.Timer(displayCallback, displayTimer, 0, 1000);
    }

    public void timeDisplay(object timerObject)
    {
        DisplayTimer t = (DisplayTimer)timerObject;


        for (int j = 0; j < t.row; j++)
        {
            string value = t.outputTime[j].ToString(timeFmt);

            if (value != "0001/01/01 00:00:00.000")
            {
                writeToTextBox(j, value);
            }
        }
    }

    public void writeToTextBox(int j, string value)
    {
        if (InvokeRequired)
        {
            BeginInvoke(new StringParameterDelegate(writeToTextBox), new object[] { j, value });
            return;
        }
        //// Must be on the UI thread if we've got this far
        textbox[1, j].Text = value;
    } 

    void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
    {
        string product = e.Product.ToString();
        int c = dictionarySymbol[product];

        displayTimer.outputTime[c] = e.TimeStamp;

        msc.fillBuffer(string.Format("{0},{1},{2},{3},{4}\r\n",
                        e.TimeStamp.ToString(timeFmt),
                        product,
                        Enum.GetName(typeof(ZenFire.TickType), e.Type),
                        e.Price,
                        e.Volume));
    }

谁能指出干扰可能在哪里?

4

2 回答 2

1

如果您在计时器回调中所做的一切都是更新 UI,我建议您System.Windows.Forms.Timer改用。您不必处理InvokeRequired/BeginInvoke因为该处理程序在 UI 线程上运行。

您似乎还为System.Thread.Timer. 这可能会导致计时器在HistoricalDownload. 这可能比您希望计时器停止运行要快得多。(请参阅http://msdn.microsoft.com/en-us/library/saba8ksx上的第一个注释)您应该将该变量放在父类的字段中 - 或者只要您愿意,任何类都将保持“活动”要运行的计时器。我认为如果您使用System.Windows.Forms.Timer. 但是,为异步使用的东西保留一个字段也是一个好主意。

于 2012-07-31T19:09:16.997 回答
0

计时器的 Tick 事件可能发生在 ThreadPool 线程上(许多框架计时器都这样做,但由于您使用的是自定义计时器(ZenFire?),因此无法确定)。

如果是这种情况,您的代码可能不是线程安全的,并且您可能会在计时器的 Tick 事件中遇到异常。同样,根据实现,异常可能会阻止计时器在该点之后正常运行。

特别要注意的是不要从计时器的 Tick 事件中更新任何 UI 组件 - 而是安装,将调用编组回 UI 线程Control.Invoke(或者Dispatcher.Invoke如果您正在使用 WPF)。另外,像使用你Dictionary<T,U>的简单的东西不是线程安全的,所以你应该同步对这些项目的访问。

于 2012-07-31T19:05:15.703 回答