我使用线程(这里只有两个用于检查)来ping我连接网络上的前8个设备。
public void testThread1()
{
// executing in thread
lstLocal.FullRowSelect = true;
bool value;
for (int i = 0; i <= 3; i++)
{
string ping_var = "192.168.1" + "." + i;
value = Ping(ping_var, 4, 4);
if (value == true)
{
ListViewItem items = new ListViewItem(ping_var.ToString());
lstLocal.Items.Add(items);
}
}
return;
}
从
调用线程 private void Form1_Load(object sender, EventArgs e)
{
lstLocal.Items.Clear();
lstLocal.View = View.Details;
ThreadStart threaddelegate1 = new ThreadStart(new Form1().testThread1);
//Calls Ping() with the same prameters as Thread1 but for next 4 devices
ThreadStart threaddelegate2 = new ThreadStart(new Form1().testThread2);
Thread newthread = new Thread(threaddelegate1);
newthread[0] = new Thread(threaddelegate1);
newthread[1] = new Thread(threaddelegate2);
foreach (Thread mythread in newthread)
{
newthread.Start();
}
}
前4个设备由thread1进行PING,最后4个由thread2进行PING。相同的函数Ping()在没有线程的情况下调用时对我有效,但会导致延迟(所以线程逼近)。
它是什么原因?我调试并发现线程没有执行,应用程序退出Form1_Load()
。
答案 0 :(得分:1)
线程正在启动,但在退出Form.Load
之前它们没有做任何工作。然后当他们做工作时,你试图从非UI线程修改UI,这将在线程中抛出异常。
如果要修改UI,则必须与UI线程同步。这通常是使用Form.Invoke
完成的。在您的代码中,如果您更改此内容:
ListViewItem items = new ListViewItem(ping_var.ToString());
lstLocal.Items.Add(items);
要
this.Invoke((MethodInvoker) delegate
{
ListViewItem items = new ListViewItem(ping_var.ToString());
lstLocal.Items.Add(items);
});
它应该适合你。有关详细信息,请参阅MethodInvoker和Invoke。
顺便说一下,你可能不需要两个线程。只有一个线程执行ping操作,它可能会正常工作。
答案 1 :(得分:1)
只需使用Ping
类的固有异步方法之一,而不是仅仅坐在那里等待网络请求完成就创建线程。您的原始代码也尝试从非UI线程更新UI,因此您需要确保不要在异步版本中执行此操作。
await
的使用使这很容易。除此之外,它会自动封送异步操作的延续,使其处于当前上下文中,在本例中是UI线程,因此您无需自己处理。
public async Task PingThings()
{
// executing in thread
lstLocal.FullRowSelect = true;
var tasks = Enumerable.Range(0, 3)
.Select(i => new Ping().SendPingAsync("192.168.1" + "." + i));
var replies = await Task.WhenAll(tasks);
foreach (var reply in replies.Where(reply => reply.Status == IPStatus.Success))
lstLocal.Items.Add(new ListViewItem(reply.Address.ToString()));
}