0

I have a program that runs on a server communicating with various web sites. One of the web sites will soon require the communication to be via http POST requests, so a new version of the program is required. Occasionally the program will need to issue a few hundred POST requests simultaneously, so making the requests asynchronously will be important for performance. I have now tried two ways of coding this, and both ways fail intermittently in exactly the same way by throwing an AccessViolationException. This happens even though the program consists entirely of managed code, so that AccessViolationExceptions should be impossible (see Microsoft's remarks on the AccessViolationException Class).

I posted a question about my first method of coding this two weeks ago (see System.AccessViolationException at ...). Since then I discovered the System.Net.Http.HttpClient class, and my second method of coding tries to use that, and hence it's completely different from the first method. The heart of the revised code looks like this:

HttpClient httpclient = new HttpClient();
// set up httpclient with headers etc
System.Threading.CancellationTokenSource cts = new System.Threading.CancellationTokenSource();
using (StringContent sc = new StringContent(stringContent)) {
    sc.Headers.ContentType = new MediaTypeWithQualityHeaderValue(ContentType);
    using (Task<HttpResponseMessage> task_postasync = httpclient.PostAsync(EndPoint, sc, cts.Token)) {
        task_postasync.Wait();
        if (!task_postasync.IsCompleted) {
            // cater for failure
        }
        using (HttpResponseMessage response = task_postasync.Result) {
            using (Task<string> task_ReadAsStringAsync = response.Content.ReadAsStringAsync()) {
                task_ReadAsStringAsync.Wait();
                if (!task_ReadAsStringAsync.IsCompleted) {
                    // cater for failure
                }
                string str = task_ReadAsStringAsync.Result;
                // str is the now the result of the http POST request :-)
            }
        }
    }
}

Both the revised and the original code work most of the time, but occasionally they both fail by throwing an AccessViolationException. Furthermore, with both code versions the location of the exception is specified as System.Threading._IOCompletionCallback.PerformIOCompletionCallback(). This suggests to me that both versions fail as a result of a hitting the same low level bug in the .Net libraries. The problem arises whether I run the code as 32 bit or 64 bit.

On the server the minimum number of completion ports in the ThreadPool defaults to 24 and the maximum number defaults to 1000. Most of the time I have been setting the minimum number to the maximum of 1000, however I still get the AccessViolationException when I leave everything at the default values.

I tried looking at where the exception gets thrown in assembler, by running with unmanaged code debugging enabled. The exception is thrown when the instruction pointer EIP is 7606336A in the following code:

76063354  nop  
76063355  nop  
76063356  nop  
76063357  nop  
76063358  mov         edi,edi  
7606335A  push        ebp  
7606335B  mov         ebp,esp  
7606335D  test        ecx,ecx  
7606335F  jne         760661DA  
76063365  push        dword ptr [ebp+8]  
76063368  call        edx  
7606336A  push        eax  
7606336B  call        dword ptr ds:[76060704h]  
76063371  nop  
76063372  nop  
76063373  nop  
76063374  nop  
76063375  nop  
76063376  mov         edi,edi  
76063378  push        ebp  
76063379  mov         ebp,esp  
7606337B  sub         esp,62Ch  
76063381  mov         eax,dword ptr ds:[761303ACh]  
76063386  xor         eax,ebp  
76063388  mov         dword ptr [ebp-4],eax  
7606338B  cmp         dword ptr [ebp+8],1  
7606338F  push        esi  
76063390  mov         esi,dword ptr [ebp+0Ch]  
76063393  je          76066AF1  
76063399  cmp         dword ptr [ebp+8],2  
7606339D  jne         760633A8  
7606339F  cmp         byte ptr ds:[76130002h],0  

The exception is thrown immediately after the line call edx and the register edx is zero, so this looks to me as though it's trying to call something with memory address zero and failing.

To help optimise large number of simultaneous web requests the program has a config file which is as follows:

<?xml version="1.0"?>
<configuration>
    <system.net>
        <connectionManagement>
            <add address="*" maxconnection="5000"/>
        </connectionManagement>
        <settings>
            <servicePointManager expect100Continue="false" useNagleAlgorithm="false"/>
        </settings>
    </system.net>
    <runtime>
        <legacyCorruptedStateExceptionsPolicy enabled="true" />
    </runtime>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
</configuration>

These have been the settings for a long time, and have been useful in the past for getting high performance with multiple requests over the internet.

I would have thought that making asynchronous http POST requests should be easy, but I don't seem to be able to avoid an intermittent AccessViolationException. Can anyone help?

Community
  • 1
  • 1
Stochastically
  • 7,616
  • 5
  • 30
  • 58
  • Have you tried using "[UseTaskFriendlySynchronizationContext](http://stackoverflow.com/questions/9562836/whats-the-meaning-of-usetaskfriendlysynchronizationcontext)"? Also you are doing Async wrong, if you are using any of the TAP async methods introduced in .NET 4.5 you should not be calling `.Wait()` or `.Result` and should be using async/await instead. – Scott Chamberlain Jan 27 '14 at 22:46
  • @ScottChamberlain thanks for your thoughts. But I'm creating .Net assemblies, so I don't think [UseTaskFriendlySynchronizationContext](http://stackoverflow.com/questions/9562836/whats-the-meaning-of-usetaskfriendlysynchronizationcontext) applies because it seems to be related to ASP. Also, I'm still in .Net 4.0 so I'm not using the await stuff because that didn't come in until .Net 4.5. – Stochastically Jan 27 '14 at 23:39

1 Answers1

1

I did something like what you're describing. I wrapped the http requests in a BackgroundWorker. You can fire up lots and lots of these and save yourself the work of all that async madness.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

Xavier J
  • 4,326
  • 1
  • 14
  • 25
  • Thanks for the suggestion, but why do you think background threads are going to be any different to threadpool threads, in terms of avoiding the `AccessViolationException` that I'm seeing? – Stochastically Jan 27 '14 at 22:14
  • Because within the background threads, you will make synchronous HTTP calls!!! (smile) and save yourself a lot of headaches. – Xavier J Jan 27 '14 at 22:17
  • Good point! Maybe I'll have to resort to that. I was under the impression that waiting for IO responses on completion ports was the recommended way of coding this stuff. However, for some reason it's not working for me :-|. – Stochastically Jan 27 '14 at 22:20