kurchavy
kurchavy

Reputation: 37

AccessViolation during async TCP operations

I'm continuously getting unhandled AccessViolationException during various async TCP operations. The exception arises only in Disassembly window in built-in function System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP). Stack trace of the exception contains only this function. Assembly line is: cmp dword ptr [ecx], ecx.
The most annoying thing is that exception arrives irregularly (program can execute 30 minutes or 6 hours or 15 seconds before it).

Here is full exception description:

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: 

The code: I've got this exception during any tries to access TCP socket async in any way. I don't use external unmanaged code. Here is my last try to connect to group of remote address asynchronously.

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;
            }
        }
    }

}

Update: The same exception raised in code reworked according Noseratio suggestions. Thread.Start was replaced with Task.Run. In

catch
{
    return null;
}

I was receiving only SocketExceptions with code 10060 (Timeout)...

Upvotes: 1

Views: 1411

Answers (1)

noseratio
noseratio

Reputation: 61736

I think the problem might be here:

new Thread(WorkerThread).Start();

// ...

async void WorkerThread() 
{
    // ...
}

Try changing it to this:

var task = Task.Run(() => WorkerThreadAsync());
task.Wait(); // for debugging

// ...

async Task WorkerThreadAsync() 
{
    // ...
}

Alternatively, don't use a separate thread at all:

var task = WorkerThreadAsync();
task.Wait(); // for debugging

You use async APIs inside WorkerThread anyway, a switch to a different pool thread will most likely occur after the first await.

A few more things:

  • Don't do this: catch { return null }. Dump the actual exception information.
  • You are disposing of the TcpClient as soon as the ConnectAsync task has completed, i.e. once the client has connected to the server: using (TcpClient c = new TcpClient()) { ... }. Are you really no longer using the TcpClient object after that?

Upvotes: 1

Related Questions