读书人

请问一个多线程编程的有关问题

发布时间: 2013-04-20 19:43:01 作者: rapoo

请教一个多线程编程的问题
小弟作业,让写一个监控局域网电脑是否在线的程序。老湿让用循环的方法ping在同一个网段的电脑,如果连续3次不能Ping通则认为该电脑不在线。

我用Listview控件表示电脑,listview.item.text表示电脑名称,listview.item.tooltip表示电脑的ip,然后还要将ping的情况实时在listview控件上显示出来,并给网管发送短信提示。

一开始我直接在form_load中执行死循环的ping,会造成界面卡死;如果新开线程执行这个耗时操作,但是我不知道如何在这个线程中如何实时的获取或设置主线程建立的控件的属性,直接运行程序会提示“线程间操作无效: 从不是创建控件ListView1的控件访问它”。轻各位大侠指教


附部分代码:


namespace 脱机监控
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
IDataReader dr;
Thread t;
private void Form1_Load(object sender, EventArgs e)
{
genlist();
Thread t = new Thread(checknetwork);
t.IsBackground = true;
t.Start();
}

public void genlist()
{
//清空lsv,防止重复生成列表
listView1.Clear();
dr = null;
//加载数据库中的监控点到ListView
using (MySqlConnection conn = new MySqlConnection(sqlconnstr))
{
conn.Open();
using (MySqlCommand cmd = new MySqlCommand("select * from checkpoint", conn))
{
dr = cmd.ExecuteReader();
//遍历记录集,将监控点信息添加到ListView中,checkpointname标记监控点,checkpointip为IP地址
while (dr.Read())
{
ListViewItem Item = new ListViewItem(dr["checkpointname"].ToString(), 0);
Item.ToolTipText = dr["checkpointip"].ToString();
listView1.Items.AddRange(new ListViewItem[] { Item });



}
dr.Close();
}
}
}

private void checknetwork()
{

while (true)
{
//autoEvent.WaitOne(); //阻塞当前线程,等待通知以继续执行
for (int i = 0; i < listView1.Items.Count; i++)
{
//开始遍历listview控件,ping遍历到的item,看看能否Ping通
Ping p1 = new Ping();
PingOptions options = new PingOptions(64, true);
disconn = 0;
for (int j = 0; j < 5; j++)
{
try
{
PingReply reply = p1.Send(listView1.Items[i].ToolTipText);//阻塞方式

//显示Ping是否成功
if (reply.Status != IPStatus.Success)
{
disconn += 1;
}


}
catch
{
disconn += 1;
}
}

if (disconn > 2)
{
//如果连续3此无法联系到监控点,认为该点脱离监控。
//将监控点图标状态改为imagelist索引1,
try
{
listView1.Items[i].ImageIndex = 1;
//已经发送了几次短信
//如果还没有发送过短信,那么向告警表写入告警日志
if (data.returnstr("select sendsmsnum from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'") == "0")
{
data.returnint("insert into alarm(checkpointip,alarm,alarmtime) values('" + listView1.Items[i].ToolTipText + "','通信中断告警!无法连接到监控点:“" + listView1.Items[i].Text + "”','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "')");
showalarm();


//向网管发送短信
sm("通信中断告警!无法连接到监控点:“" + listView1.Items[i].Text + "”,发生时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), data.returnstr("select mobile from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'"));
data.returnint("update checkpoint set sendsmsnum=1 where checkpointip='" + listView1.Items[i].ToolTipText + "'");
}
}
catch (Exception e) { MessageBox.Show("发生错误::" + e.ToString()); }
}
else
{
//如果该点上次的状态是中断的,发送通信恢复提示。判断依据:olt表的sendsmsnum==1
if (data.returnstr("select sendsmsnum from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'") == "1")
{
sm("通信恢复通知。连接到监控点“" + listView1.Items[i].Text + "”,恢复时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), data.returnstr("select mobile from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'"));
//向告警表写入告警恢复日志
data.returnint("insert into alarm(checkpointip,alarm,alarmtime) values('" + listView1.Items[i].ToolTipText + "','通信恢复通知!连接到监控点:“" + listView1.Items[i].Text + "”','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "')");


showalarm();

}
//只要能连接上设备,每次循环都要将发送短信次数设置为0
data.returnint("update checkpoint set sendsmsnum=0 where checkpointip='" + listView1.Items[i].ToolTipText + "'");
try
{
listView1.Items[i].ImageIndex = 0;
}
catch { }
}
}
}
}

}
}


[解决办法]
namespace 脱机监控
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
IDataReader dr;
Thread t;
delegate void workHanddler();
private void Form1_Load(object sender, EventArgs e)
{
genlist();
Thread t = new Thread(work);
t.IsBackground = true;
t.Start();
}

public void genlist()
{
//清空lsv,防止重复生成列表


listView1.Clear();
dr = null;
//加载数据库中的监控点到ListView
using (MySqlConnection conn = new MySqlConnection(sqlconnstr))
{
conn.Open();
using (MySqlCommand cmd = new MySqlCommand("select * from checkpoint", conn))
{
dr = cmd.ExecuteReader();
//遍历记录集,将监控点信息添加到ListView中,checkpointname标记监控点,checkpointip为IP地址
while (dr.Read())
{
ListViewItem Item = new ListViewItem(dr["checkpointname"].ToString(), 0);
Item.ToolTipText = dr["checkpointip"].ToString();
listView1.Items.AddRange(new ListViewItem[] { Item });

}
dr.Close();
}
}
}

private void work()
{
workHanddler wh=new workHanddler(checknetwork);
this.Invoke(wh);
}
private void checknetwork()
{

while (true)
{
//autoEvent.WaitOne(); //阻塞当前线程,等待通知以继续执行
for (int i = 0; i < listView1.Items.Count; i++)
{
//开始遍历listview控件,ping遍历到的item,看看能否Ping通


Ping p1 = new Ping();
PingOptions options = new PingOptions(64, true);
disconn = 0;
for (int j = 0; j < 5; j++)
{
try
{
PingReply reply = p1.Send(listView1.Items[i].ToolTipText);//阻塞方式

//显示Ping是否成功
if (reply.Status != IPStatus.Success)
{
disconn += 1;
}
}
catch
{
disconn += 1;
}
}

if (disconn > 2)
{


//如果连续3此无法联系到监控点,认为该点脱离监控。
//将监控点图标状态改为imagelist索引1,
try
{
listView1.Items[i].ImageIndex = 1;
//已经发送了几次短信
//如果还没有发送过短信,那么向告警表写入告警日志
if (data.returnstr("select sendsmsnum from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'") == "0")
{
data.returnint("insert into alarm(checkpointip,alarm,alarmtime) values('" + listView1.Items[i].ToolTipText + "','通信中断告警!无法连接到监控点:“" + listView1.Items[i].Text + "”','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "')");
showalarm();
//向网管发送短信
sm("通信中断告警!无法连接到监控点:“" + listView1.Items[i].Text + "”,发生时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), data.returnstr("select mobile from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'"));
data.returnint("update checkpoint set sendsmsnum=1 where checkpointip='" + listView1.Items[i].ToolTipText + "'");
}


}
catch (Exception e) { MessageBox.Show("发生错误::" + e.ToString()); }
}
else
{
//如果该点上次的状态是中断的,发送通信恢复提示。判断依据:olt表的sendsmsnum==1
if (data.returnstr("select sendsmsnum from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'") == "1")
{
sm("通信恢复通知。连接到监控点“" + listView1.Items[i].Text + "”,恢复时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), data.returnstr("select mobile from checkpoint where checkpointip='" + listView1.Items[i].ToolTipText + "'"));
//向告警表写入告警恢复日志
data.returnint("insert into alarm(checkpointip,alarm,alarmtime) values('" + listView1.Items[i].ToolTipText + "','通信恢复通知!连接到监控点:“" + listView1.Items[i].Text + "”','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "')");
showalarm();

}
//只要能连接上设备,每次循环都要将发送短信次数设置为0
data.returnint("update checkpoint set sendsmsnum=0 where checkpointip='" + listView1.Items[i].ToolTipText + "'");
try
{


listView1.Items[i].ImageIndex = 0;
}
catch { }
}
}
}
}

}
}


[解决办法]
将所有操作控件的地方,都BeginInvoke到UI线程中
如:


listView1.BeginInvoke((Action)(()=>{
listView1.Items[i].ImageIndex = 0;
}));

[解决办法]
在线程调用函数里加上这句:

CheckForIllegalCrossThreadCalls = false;

[解决办法]
Control.Invoke(method);注入到UI主线程
[解决办法]
引用:
二楼wodegege10解决问题,但是我不明白的是在线程中要操作主线程的控件都要这么写吗?如果主线程的窗体有一百个控件要操作,这么写岂不累死了?有更好的方法吗?

只有在子线程中的代码才需要写BeginInvoke。你写代码觉得“累死了”吗?如果没有,那么当时记得写上BeginInvoke并不会增加什么负担。而当你发现bug,那么修改是必然的,也不会累死。

读书人网 >C#

热点推荐