none
Stream Dispose when thread be abort RRS feed

  • Question

  • Dear All:

        I want to make sure a problem, but it is hard to simulate,

    when thread "A" is excuting Dispose method, another thread "B" call "A"'s Abort method.

    I know it's a problem. but i am not sure it will cause both thread "A" and "B" block/dead  ?.

    Best Regards.

    Saturday, March 30, 2013 10:23 AM

Answers

  • I modified you code slightly to look like the standard code that is on the MSDN website.  It allows more visiblility into the STATE objects than your code and also solves some threading exception errors that can occur.  I only incldued some boiler plate code in the class object so there wenren't any compiling errors.  You need to add the real code.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Excel = Microsoft.Office.Interop.Excel;
    using System.Net;
    using System.Runtime.Serialization;
    using System.Threading;
    using System.IO;
    namespace ConsoleApplication1
    {
        class ManualResetEventSlim
        {
            public ManualResetEventSlim(Boolean value)
            {
            }
            public bool Wait(int signalTimeout)
            {
                bool results = false;
                return results;
            }
            public void Dispose()
            {
            }
        }
        class MyRequestState 
        {
            public ManualResetEventSlim doneSignal = new ManualResetEventSlim(false);
            public HttpWebRequest httpRequest;
            public HttpWebResponse httpResponse;
            public Stream ResponseStream;
            public MyRequestState()
            {
            }
        }
       
        class Program
        {
     
            static void Main(string[] args)
            {
                string url = "mywebsite";
                MyRequestState httpAsyncContext = new MyRequestState();
                try
                {
                    HttpWebRequest httpRequest = CreateHttpWebRequest(url, "GET");
                    httpAsyncContext.httpRequest = httpRequest;
                    IAsyncResult result = httpRequest.BeginGetResponse(new AsyncCallback(HttpResponseCallBack), httpAsyncContext);
                    int signalTimeout = 10;
                    bool isSet = httpAsyncContext.doneSignal.Wait(signalTimeout);
     
                  }
                  catch(Exception ex)
                  {
                  }
                  finally
                  {
                    httpAsyncContext.doneSignal.Dispose();
                    httpAsyncContext.ResponseStream.Close();
                    httpAsyncContext.httpResponse.Close();
                    httpAsyncContext.httpRequest.Abort();
                  }
            }
            static HttpWebRequest CreateHttpWebRequest(string url, string method)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                return request;
            }
            private static void HttpResponseCallBack(IAsyncResult asynchronousResult)
            {
                try
                {
                    // State of request is asynchronous.
                    MyRequestState myRequestState = (MyRequestState)asynchronousResult.AsyncState;
                }
                finally
                {
                }
            }
        }
    }


    jdweng

    Tuesday, April 2, 2013 1:11 PM

All replies

  • Thread A must add a lock at the beginning of the dispose method.  See webpage below

    http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx


    jdweng

    Saturday, March 30, 2013 12:20 PM
  • if not? It will block thread B or something happen ?
    Saturday, March 30, 2013 6:20 PM
  • Of course it will temporarily block B.  B must test if A exists before calling A.  If A doesn't exist then B must handle this case in code.  The lock just make sure B doesn't send to A while the dispose is occuring.

    jdweng

    Saturday, March 30, 2013 7:25 PM
  • I should describe the problem clearly.

    There is an Network Stream Object we call it "streamObj" in thread "A", when i call streamObj.Close() in thread "A",there is another Thread "B" call thread A.Abort() to kill the thread "A".

    My puzzle is that will block thread "B"? Just temporarily? In my case, i found that thread "B" never work again. But it is occasionally, i am not sure it is caused by calling A.Abort when A is calling streamObj.Close()

    Best Regards!

    Saturday, March 30, 2013 7:52 PM
  • Of course it will temporarily block B.  B must test if A exists before calling A.  If A doesn't exist then B must handle this case in code.  The lock just make sure B doesn't send to A while the dispose is occuring.

    jdweng

    The Op isn't calling the locked method.  Abort sends an exception to thread A.  Thread B isn't blocked.
    Saturday, March 30, 2013 10:02 PM
  • I just found the webpage below which explains what is happening.  Never read this page before!

    http://msdn.microsoft.com/en-us/library/ty8d3wta.aspx


    jdweng

    Sunday, March 31, 2013 1:30 AM
  • It' is the dump analysis. Thanks

    ---------------------------------------------Dump-------------------------------------

    Thread 50 is aborting Thread 40

    Thread 50 - System ID 2868

    Entry point   0x00000000
    Create time   2013-3-25 11:43:38
    Time spent in user mode   0 Days 00:01:00.421
    Time spent in kernel mode   0 Days 00:00:13.125


    .NET Call
    Stack
    Function
    System.Threading.Thread.AbortInternal()
    System.Threading.Thread.Abort()
    XXX.SyncSendThread.ReLife()
    XXX.SyncThreadManager.AssignSyncSendThread()
    XXX.SyncThreadManager.ScheProc()---//this is a while(true) method, i found this method is block.
    System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
    System.Threading.ExecutionContext.runTryCode(System.Object)
    System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode,
    CleanupCode, System.Object)
    System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
    System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object, Boolean)
    System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
    System.Threading.ThreadHelper.ThreadStart()

    Full
    Call Stack
    Function   Source
    ntdll!ZwWaitForMultipleObjects+15  
    KERNELBASE!WaitForMultipleObjectsEx+100  
    kernel32!WaitForMultipleObjectsExImplementation+e0  
    clr!WaitForMultipleObjectsEx_SO_TOLERANT+56  
    clr!Thread::DoAppropriateAptStateWait+4d  
    clr!Thread::DoAppropriateWaitWorker+17d  
    clr!Thread::DoAppropriateWait+60  
    clr!Thread::JoinEx+d5  
    clr!Thread::UserAbort+5ea  
    clr!ThreadNative::Abort+116  
    System.Threading.Thread.Abort()  
    System.Threading.ThreadHelper.ThreadStart_Context(System.Object)  
    System.Threading.ExecutionContext.runTryCode(System.Object)  
    clr!CallDescrWorker+33  
    clr!CallDescrWorkerWithHandler+8e  
    clr!MethodDesc::CallDescr+194  
    clr!MethodDesc::CallTargetWorker+21  
    clr!MethodDescCallSite::CallWithValueTypes+1c  
    clr!ExecuteCodeWithGuaranteedCleanupHelper+bb  
    clr!ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup+138  
    System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
     
    System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
     
    System.Threading.ThreadHelper.ThreadStart()  
    clr!CallDescrWorker+33  
    clr!CallDescrWorkerWithHandler+8e  
    clr!MethodDesc::CallDescr+194  
    clr!MethodDesc::CallTargetWorker+21  
    clr!ThreadNative::KickOffThread_Worker+1e1  
    clr!Thread::DoExtraWorkForFinalizer+114  
    clr!Thread::ShouldChangeAbortToUnload+101  
    clr!Thread::ShouldChangeAbortToUnload+399  
    clr!Thread::ShouldChangeAbortToUnload+43a  
    clr!ManagedThreadBase::KickOff+15  
    clr!ThreadNative::KickOffThread+23e  
    clr!Thread::intermediateThreadProc+4b  
    kernel32!BaseThreadInitThunk+e  
    ntdll!__RtlUserThreadStart+70  

    ntdll!_RtlUserThreadStart+1b

    Thread 40 - System ID 1056

    Entry point   0x00000000
    Create time   2013-3-25 11:43:38
    Time spent in user mode   0 Days 00:07:08.437
    Time spent in kernel mode   0 Days 00:00:46.421


    This thread is
    waiting on data to be returned from another server via WinSock.

    The call
    to WinSock originated from DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr,
    Byte*, Int32, System.Net.Sockets.SocketFlags)
    and is destined for port
    80
    at IP address 200.54.10.246


    .NET Call
    Stack
    Function
    DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr, Byte*,
    Int32, System.Net.Sockets.SocketFlags)
    System.Net.UnsafeNclNativeMethods+OSSOCK.recv(IntPtr,
    Byte*, Int32, System.Net.Sockets.SocketFlags)
    System.Net.Sockets.Socket.Receive(Byte[],  Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError  ByRef)
    System.Net.Sockets.Socket.Receive(Byte[],
    Int32, Int32, System.Net.Sockets.SocketFlags)
    System.Net.Sockets.NetworkStream.Read(Byte[], Int32,
    Int32)
    System.Net.PooledStream.Read(Byte[],
    Int32, Int32)
    System.Net.ConnectStream.InternalRead(Byte[], Int32,
    Int32)
    System.Net.ConnectStream.ReadWithoutValidation(Byte[],
    Int32, Int32, Boolean)
    System.Net.ConnectStream.DrainSocket()
    System.Net.ConnectStream.CloseInternal(Boolean,
    Boolean)
    System.Net.ConnectStream.System.Net.ICloseEx.CloseEx(System.Net.CloseExState)
    System.Net.ConnectStream.Dispose(Boolean)
    System.IO.Stream.Close()
    XXX.AsyncRequestContext.Dispose()
    XXX.HttpHandler.PostDataToUrlAsync[[System.__Canon,
    mscorlib]]
    (Byte[], System.String, Int32, System.__Canon ByRef)
    XXX.PostReponse[[System.__Canon,
    mscorlib]]
    (System.String,
    XXX.PostAPIMethodName, Int32, System.__Canon
    ByRef)
    XXX.LoginOut()
    XXX.LogOut()
    XXX.CloseConnection(Smc20.Device.Com.Public.DeviceStateCloseConnectRequest)
    XXX.SendMessage(Smc20.Device.Com.Public.IDeviceMessageSender)
    XXX.SyncSendThread.Run()
    System.Threading.ThreadHelper.ThreadStart_Context(System.Object)
    System.Threading.ExecutionContext.runTryCode(System.Object)
    System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode,
    CleanupCode, System.Object)
    System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
    System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object, Boolean)
    System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
    System.Threading.ThreadHelper.ThreadStart()

    Full
    Call Stack
    Function   Source
    ntdll!ZwWaitForSingleObject+15  
    mswsock!SockWaitForSingleObject+1ba  
    mswsock!WSPRecv+2a7  
    ws2_32!recv+87  
    DomainBoundILStubClass.IL_STUB_PInvoke(IntPtr, Byte*, Int32,
    System.Net.Sockets.SocketFlags)
     
    System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32,
    System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)
     
    System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32,
    System.Net.Sockets.SocketFlags)
     
    System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)  
    System.Net.PooledStream.Read(Byte[], Int32, Int32)  
    System.Net.ConnectStream.InternalRead(Byte[], Int32, Int32)  
    System.Net.ConnectStream.ReadWithoutValidation(Byte[], Int32, Int32,
    Boolean)
     
    System.Net.ConnectStream.DrainSocket()  
    System.Net.ConnectStream.CloseInternal(Boolean, Boolean)  
    System.Net.ConnectStream.System.Net.ICloseEx.CloseEx(System.Net.CloseExState)  
    System.Net.ConnectStream.Dispose(Boolean)  
    System.IO.Stream.Close()  
    XXX.AsyncRequestContext.Dispose()  
    XXX.HttpHandler.PostDataToUrlAsync[[System.__Canon,
    mscorlib]](Byte[], System.String, Int32, System.__Canon ByRef)
     
    System.Threading.ThreadHelper.ThreadStart_Context(System.Object)  
    System.Threading.ExecutionContext.runTryCode(System.Object)  
    clr!CallDescrWorker+33  
    clr!CallDescrWorkerWithHandler+8e  
    clr!MethodDesc::CallDescr+194  
    clr!MethodDesc::CallTargetWorker+21  
    clr!MethodDescCallSite::CallWithValueTypes+1c  
    clr!ExecuteCodeWithGuaranteedCleanupHelper+bb  
    clr!ReflectionInvocation::ExecuteCodeWithGuaranteedCleanup+138  
    System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
     
    System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext,
    System.Threading.ContextCallback, System.Object)
     
    System.Threading.ThreadHelper.ThreadStart()  
    clr!CallDescrWorker+33  
    clr!CallDescrWorkerWithHandler+8e  
    clr!MethodDesc::CallDescr+194  
    clr!MethodDesc::CallTargetWorker+21  
    clr!ThreadNative::KickOffThread_Worker+1e1  
    clr!Thread::DoExtraWorkForFinalizer+114  
    clr!Thread::ShouldChangeAbortToUnload+101  
    clr!Thread::ShouldChangeAbortToUnload+399  
    clr!Thread::ShouldChangeAbortToUnload+43a  
    clr!ManagedThreadBase::KickOff+15  
    clr!ThreadNative::KickOffThread+23e  
    clr!Thread::intermediateThreadProc+4b  
    kernel32!BaseThreadInitThunk+e  
    ntdll!__RtlUserThreadStart+70  
    ntdll!_RtlUserThreadStart+1b  


    Socket properties:
    Source Port 53273
    Destination IP 200.54.10.246
    Destination Port   80
    Monday, April 1, 2013 4:29 AM
  • I paste the dump analysis ,pls take a look

    Monday, April 1, 2013 4:30 AM
  • I appears that thread 40 after doing a dispose attempts to read the stream again.  thsi reads the socket and calls the Pinvoke method.  You need to figure out why after thread 40 does the dispose() it continues to read the sttream.

    jdweng

    Monday, April 1, 2013 9:32 AM
  • Yes, i doubt this is a problem. the Stream Read is a asyncOperation, and there's another thread call the stream dispose method

    But it will cause the thread block? In dump analysis, it can't find any critical section.

    Monday, April 1, 2013 11:16 AM
  • There is a Sync read (not Async) in the dump

    System.Net.PooledStream.Read(Byte[], Int32, Int32)


    jdweng

    Monday, April 1, 2013 11:19 AM
  • This is call from Dispose method, And i don't know why.

    what i means "asyncOperation" is that i use stream as  【httpWebRequest.BeginGetRequestStream】

    【httpWebRequest.BeginGetResponse】【Stream.BeginRead】

    I guess the BeginXXX is not completed, however, another thread which call "Dispose" is times up.

    Monday, April 1, 2013 11:29 AM
  • Read is blocking.  So you must test if the byte count is greater than 0 before doing a read in a Async Event.  There are cases where you can have a race condition in a Async Event like when another thread closes the object between the event is set and the call to the event.


    Monday, April 1, 2013 11:43 AM
  • How do you know Read is blocking? There's no critical section in dump.

    【So you must test if the byte count is creater than 0 before doing a read in a Async Event.】I don't know what you exactly mean, Could you make a example? Thanks

    My code as below:

     private void ReadStreamCallBack(IAsyncResult streamResult)
            {

     int read = responseStream.EndRead(streamResult);
                    // Read the HTML page and then print it to the console.
                    if (read > 0)
                    {

                         ............

                       IAsyncResult asynchronousResult = responseStream.BeginRead(requestContext.BufferRead, 0, requestContext.BufferRead.Length, new AsyncCallback(ReadStreamCallBack), requestContext);
                        return;
                    }
                    else
                    {//Completed

                        requestContext.HttpResponse.Close();
                    }

    }

    Monday, April 1, 2013 11:56 AM
  • Can you post your code that calls the ReadStreamCallBack.  I want to see the object that is pass to the IAsyncResult.  You shouldn't be using streamResult in the ReadStreamCallback.  You should be using streamResult.AsyncState to prevent a race condition.  You also should be using EndRead (a blocking function) in a ReadStreamCallBack.  EndRead() waits until the stream closes.  You also shouldn't have a BeginRead in a ReadStreamCallBack.

    Any READ method is blocking.  Only AsyncRead is non blocking.

    BeginRead is used when waiting for a connection to connect and then you start the ReadStreamCallBack inside the Asyn BeginRead Callback function.  Likewise,  EndRead() is meant to be used after you close the connecton when you want to make surre you get all the data out of the connection before you dispose the stream object.  So your function should be something like this

    Client

    1) Start BeginRead Callback

    2) Start BeginDisconnect

    3) Connect

    4) In BeginRead Callback start ReadStreamCallBack

    5) ReadStreamCallBack just read data

    6) In BeginDisconnect call EndRead()

    See webpages below

    http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.90).aspx

    http://msdn.microsoft.com/en-us/library/fx6588te(v=vs.90).aspx

    The webpage below shows all 4 methods

    1) Sync client

    2) Sync server

    3) Async client

    4) Async server

    http://msdn.microsoft.com/en-us/library/w89fhyex(v=vs.90).aspx


    jdweng

    Monday, April 1, 2013 1:26 PM
  • Tuesday, April 2, 2013 2:03 AM
  • the difference betsween yoour link and mine is just the version of Net Library.  Your example is a partial example for BeginRead Method while my is a complete socket example showing more than just the Begin read Method.

    Your callback function doesn't use the Async state parameter.  See below

     private void ReadStreamCallBack(IAsyncResult streamResult)
            {
     int read = responseStream.EndRead(streamResult);

    The example callback uses the following

    private static void RespCallback(IAsyncResult asynchronousResult)
      {  
        try
        {
          // State of request is asynchronous.
          RequestState myRequestState=(RequestState) asynchronousResult.AsyncState;
    Extracting the state object (the stream) may be the key to the problem.  Having access to the stream properties will give you the option to verify if the stream is still open and if the stream contains data.


    jdweng

    Tuesday, April 2, 2013 10:46 AM
  • Sorry, I just elide this code.

    Cuz the company security, i can't paste the full code.

    But the difference between my【Async state parameter】 and msdn's is that There's a 【ManualResetEventSlim】field which is a signal to tell another thread the the asycnRead is completed.

    My Code is like bellow:

    public bool Get(string url,int timeout)

    ManualResetEventSlim doneSignal = new ManualResetEventSlim(false);
                MyRequestState httpAsyncContext = new MyRequestState(doneSignal);
                try
                {
                    HttpWebRequest httpRequest = CreateHttpWebRequest(url, "GET");
                    httpAsyncContext.HttpRequest = httpRequest;
                    IAsyncResult result = httpRequest.BeginGetResponse(new AsyncCallback(HttpResponseCallBack), httpAsyncContext);

                    //等待异步IO异步线程
                    bool isSet = doneSignal.Wait(signalTimeout);

                    ..............

                    ..............

                  }

                  catch(Exception ex)

                  {

                  }

                  finally

                  {

                    doneSignal.Dispose();
                    httpAsyncContext.ResponseStream.Close();

                    httpAsyncContext.HttpResponse.Close();

                    httpAsyncContext.HttpRequest.Abort();

                  }

    I doubt the multiThread access the stream maybe the key of problem, but i can't find any theoretics to prove it, and there'is no deadlock(critical section) in dump.

    Tuesday, April 2, 2013 12:02 PM
  • I modified you code slightly to look like the standard code that is on the MSDN website.  It allows more visiblility into the STATE objects than your code and also solves some threading exception errors that can occur.  I only incldued some boiler plate code in the class object so there wenren't any compiling errors.  You need to add the real code.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Excel = Microsoft.Office.Interop.Excel;
    using System.Net;
    using System.Runtime.Serialization;
    using System.Threading;
    using System.IO;
    namespace ConsoleApplication1
    {
        class ManualResetEventSlim
        {
            public ManualResetEventSlim(Boolean value)
            {
            }
            public bool Wait(int signalTimeout)
            {
                bool results = false;
                return results;
            }
            public void Dispose()
            {
            }
        }
        class MyRequestState 
        {
            public ManualResetEventSlim doneSignal = new ManualResetEventSlim(false);
            public HttpWebRequest httpRequest;
            public HttpWebResponse httpResponse;
            public Stream ResponseStream;
            public MyRequestState()
            {
            }
        }
       
        class Program
        {
     
            static void Main(string[] args)
            {
                string url = "mywebsite";
                MyRequestState httpAsyncContext = new MyRequestState();
                try
                {
                    HttpWebRequest httpRequest = CreateHttpWebRequest(url, "GET");
                    httpAsyncContext.httpRequest = httpRequest;
                    IAsyncResult result = httpRequest.BeginGetResponse(new AsyncCallback(HttpResponseCallBack), httpAsyncContext);
                    int signalTimeout = 10;
                    bool isSet = httpAsyncContext.doneSignal.Wait(signalTimeout);
     
                  }
                  catch(Exception ex)
                  {
                  }
                  finally
                  {
                    httpAsyncContext.doneSignal.Dispose();
                    httpAsyncContext.ResponseStream.Close();
                    httpAsyncContext.httpResponse.Close();
                    httpAsyncContext.httpRequest.Abort();
                  }
            }
            static HttpWebRequest CreateHttpWebRequest(string url, string method)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                return request;
            }
            private static void HttpResponseCallBack(IAsyncResult asynchronousResult)
            {
                try
                {
                    // State of request is asynchronous.
                    MyRequestState myRequestState = (MyRequestState)asynchronousResult.AsyncState;
                }
                finally
                {
                }
            }
        }
    }


    jdweng

    Tuesday, April 2, 2013 1:11 PM