我需要对多线程编程模型进行一些澄清,因为我很少需要处理它(大部分时间我都在做网络编程)。
来路
我有一个我用 C# 编写的程序,基本上它是一个数据监视器,并在数据库上执行每个特定的时间量,比如 1 分钟。
这个应用程序是如何相对简单的,我决定使用一个整体结构,我制作了类范围内的所有 GUI,我制作了一个处理连接和数据检索的对象。
为了处理池时间的要求,我使用了 a System.Timers.Timer
,它基本上是一个带有触发定时事件的 Thread 包装,在这里我执行了数据池。
当找到新数据时,我需要从定时器触发的函数(根据定义在其他线程中)触发属于 GUI(现在在主线程中运行)的 X 类中的方法。
第一次尝试直接调用定时器触发的方法,导致跨线程错误:因为方法驻留在X类中,没有在定时器线程中构造。
然后我再次尝试使用其他方法。我在类中使用他各自的委托创建了一个事件,该委托读取数据并将 GUI 对象订阅到该事件。
问题
现在,当我触发事件时,.net 会产生一个异常,告诉我发送者对象实例为空,完全不知道为什么,但我怀疑这是因为对象本身是使用主线程中的 GUI 对象创建的,当我决定从另一个线程发送对象(它正在生成事件),实例根本不存在,因为没有在那里创建。
这是计时器到期时调用的函数:
private void PoolearMensajes(object Sender, ElapsedEventArgs e)
{
try
{
pRdr.getPendingMessages(); <--- This function creates the exception
if (pRdr.MensajesPendientes > 0)
{
this.oSysIcon.Text = pRdr.MensajesPendientes.ToString() + " tickets pendientes";
this.oSysIcon.BalloonTipIcon = ToolTipIcon.Info;
this.oSysIcon.BalloonTipText = pRdr.MensajesPendientes.ToString() + " tickets pendientes";
this.oSysIcon.BalloonTipTitle = "Información";
this.oSysIcon.ShowBalloonTip(3000);
System.Media.SystemSounds.Exclamation.Play();
}
}
catch (Exception ex)
{
this.oSysIcon.BalloonTipTitle = "Error";
this.oSysIcon.Text = "Ha ocurrido un error.";
this.oSysIcon.BalloonTipIcon = ToolTipIcon.Error;
this.oSysIcon.BalloonTipText = ex.Message;
this.oSysIcon.ShowBalloonTip(3000);
System.Media.SystemSounds.Exclamation.Play();
}
}
这是驻留在主线程中创建的数据检索器对象中的方法:
public delegate void TicketsFoundHandler(object sender, TicketEventArgs ta);
public event TicketsFoundHandler TicketsFound;
public void getPendingMessages()
{
string sSQL;
sSQL = " an SQL Query that counts rows;";
oCmd = new SqlCommand(sSQL, oConn);
oConn.Open();
this.i_pendmsg = (int)oCmd.ExecuteScalar();
if (this.i_pendmsg > 0)
{
TicketEventArgs ta = new TicketEventArgs("", this.i_pendmsg);
TicketsFound(this, ta); <---- ERROR!
}
oConn.Close();
}
错误消息是:Object reference not set to an instance of an object
。
任何想法,任何改进,或者我没有考虑过的东西?