Gvs*_*Gvs 6 c# events asynchronous ping
陷入一个奇怪的"问题".有一个应用程序pinging整个网络.工作得很好,直到你到达一个255.255.0.0网络掩码的网络(这是65k +地址).
我发这样的话:
foreach (string str in ListContainingAddresses)
{
using (Ping ping = new Ping())
{
if (pingCounter == 10000) { Thread.Sleep(10000); pingCounter = 0; }
//Make an eventhandler
ping.PingCompleted += new PingCompletedEventHandler(pingCompleted);
//Send the pings asynchronously
ping.SendAsync(IPAddress.Parse(str), 1000);
sentPings++;
//This counts pings being sent out
pingCounter++;
}
}
Run Code Online (Sandbox Code Playgroud)
并像这样回忆他们:
public void pingCompleted(object sender, PingCompletedEventArgs e)
{
//This counts recieved addresses
recievedIpAddresses++;
if (e.Reply.Status == IPStatus.Success)
{
//Do something
}
else
{
/*Computer is down*/
}
//This checks if sent equals recieved
if (recievedIpAddresses == sentPings )
{
//All returned
}
}
Run Code Online (Sandbox Code Playgroud)
问题是a)有时(很少)它没有完成(条件不符合).b)什么时候完成数字不匹配?如果我打印发送和收到刚才他们是
Sent: 65025 Recieved: 64990
Run Code Online (Sandbox Code Playgroud)
尽管如此,条件得到满足并且应用仍在继续?我不知道为什么以及如何发生这种情况.代码是否快速执行,以便应用程序更新两个整数?沿途会有一些丢失吗?如果我在具有255个地址的子网上尝试它,这个问题永远不会发生.自.NET 3.5以来,不能使用CountDownEvent而不是变量
你有任何锁定吗?这看起来像你的问题.我可以在您的代码中看到各种竞争条件和内存处理器缓存问题.
尝试lock用来保护recievedIpAddresses == sentPings和
sentPings++;
//This counts pings being sent out
pingCounter++;
Run Code Online (Sandbox Code Playgroud)
lock例如:
private readonly object SyncRoot = new object();
public void MainMethod()
{
foreach (string str in ListContainingAddresses)
{ ... }
lock (SyncRoot) { sentPings++; }
....
}
public void pingCompleted(object sender, PingCompletedEventArgs e)
{
//This counts recieved addresses
lock (SyncRoot) { recievedIpAddresses++; } // lock this if it is used on other threads
if (e.Reply.Status == IPStatus.Success)
{
//Do something
}
else
{
/*Computer is down*/
}
lock (SyncRoot) { // lock this to ensure reading the right value of sentPings
//This checks if sent equals recieved
if (recievedIpAddresses == sentPings )
{
//All returned
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的示例将强制从共享内存中读取和写入,以便不同的CPU内核不会读取不同的值.但是,根据您的代码,您可能需要更多的粗粒度锁定,其中第一个循环保护两个sentPings和pingCounter一个lock,甚至第二个方法完全受到保护lock.
人们可以说不使用lock因为它会导致性能问题,而且免费锁定非常时髦.在lock大多数情况下,底线比其他替代方案更简单.您可能需要使锁定比上面的样本更粗糙,因为您可能也有竞争条件.如果没有看到整个程序,很难提供更好的样本.
Interlocked.Incrementlock这里使用的主要原因是强制每次读取和写入来自内存,而不是CPU缓存,因此您应该获得一致的值.锁定的替代方法是使用Interlocked.Increment,但如果您在两个单独的变量上使用它,则需要仔细观察竞争条件.
(编辑)
即使你锁定你可能有问题.观看13个目标地址的时间表(不幸的是).如果你不熟悉这是为什么,那么看看"管理线程基础知识"和"C#中的线程 - Joseph Albahari"
sentPings++sentPings++现在等于13)recievedIpAddresses == sentPings测试 - 现在因为不相等而失败pingCompleted并进行recievedIpAddresses++;您需要在代码中仔细观察此类型的竞争条件,并相应地进行调整.线程的全部内容是它们与操作重叠.
脚注:
为什么SyncRoot声明为:private readonly object SyncRoot = new object();?
static控制台应用程序,它将需要static.但是,如果你static在一个类中使用,那么每个实例都将锁定同一个对象,因此会有争用readonly声明意图,并阻止您(或其他团队成员)稍后覆盖它object:
SyncRoot一个例子; Visual Studio历来称之为它的片段| 归档时间: |
|
| 查看次数: |
7494 次 |
| 最近记录: |