关于静态窗体定时器的线程运行

来源:互联网 发布:mac上玩qq游戏 编辑:程序博客网 时间:2024/06/04 20:42

最近遇到一个问题,在窗体中定义了一个静态的窗体定时器,用来查询设备的启动状态,当设备启动后,自动更新软件控件的使能,但是也是由于这个静态的定时器,导致了问题的存在。
每次更改设备时,都会重新生成一个窗体
 // 增加设备信息窗口      
        private void btnToolSysDevInfo_Click(object sender, EventArgs e)
        {
            List<string> timerrunning;
            //CTimerManagement CTimer = new CTimerManagement();
            timerrunning = timerManager.GetEnabledTimers();
            if (((timerrunning.Count == 1) && (timerrunning.Contains(CGlobalValue.CONST_STR_TIMER_IQUIRE_STATE))) || (timerrunning.Count == 0))
            {
                frmInfo mInfo = new frmInfo(this);//生成新的窗体
                mInfo.StartPosition = this.StartPosition;
                mInfo.ShowDialog(this);
            }
            else
            {
                MessageBoxEx.Show(this, Properties.Resource.STR_CLOSE_MEASURE_BEFORE_USE);
            }
        }

我在frmInfo中定义了


        /// <summary>
        /// 查询灯状态信息的定时器
        /// </summary>
        private static System.Windows.Forms.Timer m_QryTimer;


并且实例化了定时器事件:


 /// <summary>
        /// 查询灯状态定时器处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void m_QryTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                //执行查询动作
                QueryLampStatus();

                //氘灯钨灯控制都已经结束,则应该停止定时器
                if ((m_bD2Ctrl == false) && (m_bWCtrl == false))
                {
                    //停止定时器
                    m_QryTimer.Stop();
                }

                m_s32TimerTickCnt++;

                if (m_s32TimerTickCnt >= QRY_LAMP_STATUS_TRY_CNT)
                {
                    //停止定时器
                    m_QryTimer.Stop();

                    //重试次数已经结束,仍然未能点亮氘灯
                    if (m_bD2Ctrl)
                    {
                        //允许用户再次进行点灯操作
                        m_bD2Ctrl = false;
                        UpdateD2CtrlDisp();
                    }

                    //重试次数已经结束,仍然未能点亮钨灯
                    if (m_bWCtrl)
                    {
                        //允许用户再次进行点灯操作
                        m_bWCtrl = false;
                        UpdateWCtrlDisp();
                    }
                }

            }
            catch
            {
            }
        }

每次启动窗体时会判断定时器是否为空,为空则重新生成定时器,由于定时器是静态变量,所以只有第一次生成窗体时会生成定时器,其他的生成窗体都是使用之前的定时器,问题出现了,当第一次启动窗体后,定时器生成完成,然后关闭窗体,定时器并没有释放,仍然继续存在。当触发定时器使能运行时,
private void swbtnWSwitch_ValueChanged(object sender, EventArgs e)
        {
            m_frmMain.timerManager.DisableTimer(CGlobalValue.CONST_STR_TIMER_IQUIRE_STATE);
            // 延迟200ms
            System.Threading.Thread.Sleep(CGlobalValue.CONST_COM_DELAY_TIME_200MS);

            m_frmMain.VisaCom.m_lstSendBuffer.Clear();
            m_frmMain.VisaCom.m_lstRecvBuffer.Clear();

            try
            {
                string strCmd;

                //根据当前灯状态,决定发送的命令是开灯还是关灯
                if (swbtnWSwitch.Value == true)
                {
                    //发送开灯命令
                    strCmd = CGlobalCommand.STR_CMD_TUN_CTRL + CGlobalCommand.STR_CMD_BLANK + CGlobalCommand.STR_CMD_LAMP_CTRL_OPEN;
                    JobLogDataSet.WriteLog(LogType.WARNING, "DIAG", "Tungsten lamp", "User try to turn on the Tungsten lamp");
                }
                else
                {
                    //发送关灯命令
                    strCmd = CGlobalCommand.STR_CMD_TUN_CTRL + CGlobalCommand.STR_CMD_BLANK + CGlobalCommand.STR_CMD_LAMP_CTRL_CLOSE;
                    JobLogDataSet.WriteLog(LogType.WARNING, "DIAG", "Tungsten lamp", "User try to turn off the Tungsten lamp");
                }

                //同时查询灯状态,便于更新显示
                strCmd += CGlobalCommand.STR_CMD_SEPARATOR + CGlobalCommand.STR_CMD_LAMP_TUN_QRY;
                strCmd += CGlobalCommand.STR_CMD_ENDMARK;

                string strRsp;

                m_frmMain.VisaCom.SendCommand(strCmd, CGlobalValue.CONST_COM_WAIT_TIME_2000MS, out strRsp);

                //解析返回值
                if (strRsp != null)
                {
                    UpdateWLampInfo(strRsp);

                    if (swbtnWSwitch.Value == true)
                    {
                        //发送控制命令以后需要等待一段时间才能操作
                        swbtnWSwitch.Enabled = false;
                        //Begin:Added by lianzhonglin Bug1617 20130703
                        //钨灯启动时,停止氘灯和钨灯的操作
                        swbtnD2Switch.Enabled = false;
                        //End:Added by lianzhonglin
                        m_bWCtrl = true;

                        //启动定时器
                        m_s32TimerTickCnt = 0;
                        m_QryTimer.Start();//定时器触发

                        MessageBoxEx.Show(Properties.Resource.STR_INFO_LAMP_CTRL_WAIT);
                    }
                    else
                    {
                        //关灯命令可以立即执行完成
                        QueryLampStatus();
                        //Begin:Added by lianzhonglin Bug1617 20130703
                        //关灯操作时等待1s
                        Thread.Sleep(1000);
                        //End:Added by lianzhonglin
                    }
                }
            }
            catch
            {
            }
            m_frmMain.timerManager.EnableTimer(CGlobalValue.CONST_STR_TIMER_IQUIRE_STATE, true);
        }

        private void swbtnD2Switch_ValueChanged(object sender, EventArgs e)
        {
            m_frmMain.timerManager.DisableTimer(CGlobalValue.CONST_STR_TIMER_IQUIRE_STATE);
            // 延迟200ms
            System.Threading.Thread.Sleep(CGlobalValue.CONST_COM_DELAY_TIME_200MS);

            m_frmMain.VisaCom.m_lstSendBuffer.Clear();
            m_frmMain.VisaCom.m_lstRecvBuffer.Clear();

            try
            {
                string strCmd;

                //根据当前灯状态,决定发送的命令是开灯还是关灯
                if (swbtnD2Switch.Value == true)
                {
                    //发送开灯命令
                    strCmd = CGlobalCommand.STR_CMD_DEU_CTRL + CGlobalCommand.STR_CMD_BLANK + CGlobalCommand.STR_CMD_LAMP_CTRL_OPEN;
                    JobLogDataSet.WriteLog(LogType.WARNING, "DIAG", "Deuterium lamp", "User try to turn on the Deuterium lamp");
                }
                else
                {
                    //发送关灯命令
                    strCmd = CGlobalCommand.STR_CMD_DEU_CTRL + CGlobalCommand.STR_CMD_BLANK + CGlobalCommand.STR_CMD_LAMP_CTRL_CLOSE;
                    JobLogDataSet.WriteLog(LogType.WARNING, "DIAG", "Deuterium lamp", "User try to turn off the Deuterium lamp");
                }

                //同时查询灯状态,便于更新显示
                strCmd += CGlobalCommand.STR_CMD_SEPARATOR + CGlobalCommand.STR_CMD_LAMP_DEU_QRY;
                strCmd += CGlobalCommand.STR_CMD_ENDMARK;

                string strRsp;

                m_frmMain.VisaCom.SendCommand(strCmd, CGlobalValue.CONST_COM_WAIT_TIME_2000MS, out strRsp);

                //解析返回值
                if (strRsp != null)
                {
                    UpdateD2LampInfo(strRsp);

                    if (swbtnD2Switch.Value == true)
                    {
                        //发送控制命令以后需要等待一段时间才能操作
                        swbtnD2Switch.Enabled = false;
                        //Begin:Added by lianzhonglin Bug1617 20130703
                        //氘灯启动时,停止氘灯和钨灯的操作
                        swbtnWSwitch.Enabled = false;
                        //End:Added by lianzhonglin
                        m_bD2Ctrl = true;

                        //启动定时器
                        m_s32TimerTickCnt = 0;
                        m_QryTimer.Start();//定时器触发

                        MessageBoxEx.Show(Properties.Resource.STR_INFO_LAMP_CTRL_WAIT);
                    }
                    else
                    {
                        //关灯命令可以立即执行完成
                        QueryLampStatus();
                        //Begin:Added by lianzhonglin Bug1617 20130703
                        //关灯操作时等待1s
                        Thread.Sleep(1000);
                        //End:Added by lianzhonglin
                    }
                }
            }
            catch
            {
            }
            m_frmMain.timerManager.EnableTimer(CGlobalValue.CONST_STR_TIMER_IQUIRE_STATE, true);
        }
即使关闭窗体,定时器线程仍然存在,会挂靠在主线程中运行(Main())。当再次打开窗体时,对控件进行操作,并用定时器更新使能时,通过监视器发现即使在新的窗体中将 swbtnD2Switch.Enabled = false; swbtnWSwitch.Enabled = false;当运行到m_QryTimer_Tick()函数时会自动的将swbtnD2Switch.Enabled = true;swbtnWSwitch.Enabled = true;原因是第一次窗体关闭后,线程仍然存在,会继续执行定时器事件,同时更新第一次打开的页面的控件使能,无论后续打开多少次,定时器事件只更新第一次的窗体控件使能,后续打开的窗体的使能不会再被更新了。


修改的方法有很多:

1、只定义一次窗体生成,当关闭时,隐藏窗体;

2、将静态的定时器改为非静态(但是这不是我要的效果);

3、每次生成新的窗体时,查看定时器使能是否为false;即执行了stop事件,然后重新生成定时器

  if (m_QryTimer != null && m_QryTimer.Enabled == false)
            {
                m_QryTimer = null;
            }

这种方法能解决部分问题,但是还不完全。

原创粉丝点击