在各种异步TCP操作期间,我不断处理未处理AccessViolationException
。
只有在内置函数的反汇编窗口中才会出现异常
System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
。异常的堆栈跟踪仅包含此功能。装配线是:cmp dword ptr [ecx], ecx
。
最烦人的是异常到达不正常(程序可以执行30分钟或6小时或15秒)。
以下是完整的异常说明:
System.AccessViolationException unhandled
HResult=-2147467261
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=mscorlib
StackTrace:
in System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
InnerException:
代码: 在任何尝试以任何方式访问TCP套接字异步期间,我都遇到此异常。我不使用外部非托管代码。这是我最后一次尝试以异步方式连接到远程地址组。
class Program
{
static void Main(string[] args)
{
PollerCore p = new PollerCore();
p.Start();
Console.ReadLine();
}
}
public class PollerCore
{
string[] ip = new string[255];
public void Start()
{
for (int i = 1; i < 255; i++)
{
ip[i] = String.Format("192.168.100.{0}", i);
}
new Thread(WorkerThread).Start();
}
async void WorkerThread()
{
while (true)
{
Console.WriteLine("In wt... ");
DateTime dt = DateTime.Now;
List<Task<string>> tasks = new List<Task<string>>();
foreach (string addr in ip)
{
if (String.IsNullOrEmpty(addr)) continue;
tasks.Add(ConnectToDevice(addr));
}
string[] res = await Task.WhenAll(tasks.ToArray());
foreach (string s in res)
{
if (s != null) Console.WriteLine("Connecting to {0}... DONE", s);
}
Thread.Sleep(100);
}
}
async Task<string> ConnectToDevice(string ip)
{
using (TcpClient c = new TcpClient())
{
try
{
await c.ConnectAsync(ip, 5100);
return ip;
}
catch
{
return null;
}
}
}
}
更新: 根据 Noseratio 建议重新编写代码中引发的相同异常。 Thread.Start已替换为Task.Run。在
catch
{
return null;
}
我只收到代码为10060(超时)的SocketExceptions ...
答案 0 :(得分:1)
我认为问题可能在这里:
new Thread(WorkerThread).Start();
// ...
async void WorkerThread()
{
// ...
}
尝试将其更改为:
var task = Task.Run(() => WorkerThreadAsync());
task.Wait(); // for debugging
// ...
async Task WorkerThreadAsync()
{
// ...
}
或者,根本不要使用单独的线程:
var task = WorkerThreadAsync();
task.Wait(); // for debugging
无论如何,您在WorkerThread
内使用异步API,在第一个await
之后很可能会切换到另一个池线程。
还有一些事情:
catch { return null }
。转储实际的异常信息。TcpClient
任务完成后,即一旦客户端连接到服务器后,您就会处置ConnectAsync
:using (TcpClient c = new TcpClient()) { ... }
。你之后真的不再使用TcpClient
对象吗?