Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. .NET (Core and Framework)
  4. threading: always call delegate.EndInvoke?

threading: always call delegate.EndInvoke?

Scheduled Pinned Locked Moved .NET (Core and Framework)
comtutorialquestion
3 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Mr PoorEnglish
    wrote on last edited by
    #1

    Hi audience! on several places ther is demanded in a very unconditional manner: "when starting a thread with aDelegate.BeginInvoke() always call the corresponding aDelegate.EndInvoke(IAsyncResult ar).
    For example see MSDN itself [ ^ ] .
    But now i look in Reflector, how the Backgroundworker-class works, and i find:

    public void RunWorkerAsync(object argument)
    {
    if (this.isRunning)
    {
    throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerAlreadyRunning"));
    }
    this.isRunning = true;
    this.cancellationPending = false;
    this.asyncOperation = AsyncOperationManager.CreateOperation(null);
    this.threadStart.BeginInvoke(argument, null, null);
    }

    And this.threadStart is simply a private class-variable of type WorkerThreadStartDelegate, which is defined as:

    private delegate void WorkerThreadStartDelegate(object argument);

    Since

    this.threadStart.BeginInvoke(argument, null, null);
    

    does not save the returned IAsyncResult, nor passes an AsyncCallback to the BeginInvoke()-call, i see no option for the backgroundworker, to call this.threadStart.EndInvoke(IAsyncResult ar) propperly.

    So i think to myself: if the parallel processed method is void, actually there is no need to call aDelegate.EndInvoke(IAsyncResult ar)?
    I would be pleased of that, because that could simplyfy some of my codes.

    So can anyone confirm my conclusion?

    A 1 Reply Last reply
    0
    • M Mr PoorEnglish

      Hi audience! on several places ther is demanded in a very unconditional manner: "when starting a thread with aDelegate.BeginInvoke() always call the corresponding aDelegate.EndInvoke(IAsyncResult ar).
      For example see MSDN itself [ ^ ] .
      But now i look in Reflector, how the Backgroundworker-class works, and i find:

      public void RunWorkerAsync(object argument)
      {
      if (this.isRunning)
      {
      throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerAlreadyRunning"));
      }
      this.isRunning = true;
      this.cancellationPending = false;
      this.asyncOperation = AsyncOperationManager.CreateOperation(null);
      this.threadStart.BeginInvoke(argument, null, null);
      }

      And this.threadStart is simply a private class-variable of type WorkerThreadStartDelegate, which is defined as:

      private delegate void WorkerThreadStartDelegate(object argument);

      Since

      this.threadStart.BeginInvoke(argument, null, null);
      

      does not save the returned IAsyncResult, nor passes an AsyncCallback to the BeginInvoke()-call, i see no option for the backgroundworker, to call this.threadStart.EndInvoke(IAsyncResult ar) propperly.

      So i think to myself: if the parallel processed method is void, actually there is no need to call aDelegate.EndInvoke(IAsyncResult ar)?
      I would be pleased of that, because that could simplyfy some of my codes.

      So can anyone confirm my conclusion?

      A Offline
      A Offline
      Alan N
      wrote on last edited by
      #2

      I think you've been reading MSDN far too closely and I should state at the outset that I don't have an answer to the question. The confusion around this issue must arise out of inconsistencies in the Microsoft documentation. For example, there is a disparity between your reference and the information in Event Based Asynchronous Pattern[^]. The first gives the impression that the world will end if the EndInvoke call is omitted, yet the second does just that and does not explain why we're still here. I haven't found an example that demonstrates a problem caused by not calling EndInvoke or been able to come up with one of my own. My own best idea to make something go wrong was this:

      internal void InvokeTest(Int32 count) {
        IAsyncResult ar;
        for (Int32 i = 0; i < count; i++) {
          TaskDelegate t = Task;
          ar = t.BeginInvoke(null, null);
          ar.AsyncWaitHandle.WaitOne();
        }
      }
      
      private void Task() {
        // create a big exception object 
        throw new Exception('a', 64 \* 1024);
      }
      

      I thought that the ignored exceptions on the invoked thread might be retained by the CLR until EndInvoke was called but find that there is no gradual upwards drift in memory useage (Process Explorer). If the Exception objects were not being collected it should be very obvious given the size of the associated exception message. To err on the side of caution one should include EndInvoke but I can't find any compelling evidence one way or the other. So no help from me then, but I thought your post was looking lonely! Alan.

      M 1 Reply Last reply
      0
      • A Alan N

        I think you've been reading MSDN far too closely and I should state at the outset that I don't have an answer to the question. The confusion around this issue must arise out of inconsistencies in the Microsoft documentation. For example, there is a disparity between your reference and the information in Event Based Asynchronous Pattern[^]. The first gives the impression that the world will end if the EndInvoke call is omitted, yet the second does just that and does not explain why we're still here. I haven't found an example that demonstrates a problem caused by not calling EndInvoke or been able to come up with one of my own. My own best idea to make something go wrong was this:

        internal void InvokeTest(Int32 count) {
          IAsyncResult ar;
          for (Int32 i = 0; i < count; i++) {
            TaskDelegate t = Task;
            ar = t.BeginInvoke(null, null);
            ar.AsyncWaitHandle.WaitOne();
          }
        }
        
        private void Task() {
          // create a big exception object 
          throw new Exception('a', 64 \* 1024);
        }
        

        I thought that the ignored exceptions on the invoked thread might be retained by the CLR until EndInvoke was called but find that there is no gradual upwards drift in memory useage (Process Explorer). If the Exception objects were not being collected it should be very obvious given the size of the associated exception message. To err on the side of caution one should include EndInvoke but I can't find any compelling evidence one way or the other. So no help from me then, but I thought your post was looking lonely! Alan.

        M Offline
        M Offline
        Mr PoorEnglish
        wrote on last edited by
        #3

        Thank you very much! Especially

        Alan N wrote:

        ...but I thought your post was looking lonely! ...

        shows a noble character, and i'm happy to see, such magnanimity still exists in the real world :) . Finally i found an answer, and a reasonable reason to call Action<whatever>.EndInvoke(): Exceptions of the sideThread are saved to the calling thread (May be you knew that already, to me it's new). In Designmode there is no difference - the Debugger stops where the exception is thrown. But in Release-mode it's important, and very dangerous, because a lost exception leaves the program running in an instable State!

        using System.Windows.Forms;
        using System;
        using System.Threading;

        namespace AsyncWorkerCs {
        public partial class frmMain : Form {

          \[STAThread\]
          static void Main() {
             Application.EnableVisualStyles();
             Application.Run(new frmMain());
          }
        
          public frmMain() {
             InitializeComponent();
             btCreateError.Click += btCreateError\_Click;
          }
        
          void btCreateError\_Click(object sender, EventArgs e) {
             var createError = new Action(CreateError);
        
             // in Release-mode this will crash the app (recommended behavior if an unhandled exception occurs).
             //createError.BeginInvoke(createError.EndInvoke, null);
        
             // in Release-mode this will cause no Exception, but leave the app running in an undefined state!
             createError.BeginInvoke(null, null);          
          }
        
          void CreateError() {
             Thread.Sleep(500);
             throw new Exception("CreateError()!");    // in Debug-mode IDE always will stop here
          }
        

        }
        }

        Hmm, now i've found a reason to call Action.EndInvoke, it's one more reason to deprecate the Backgroundworker-class, isn't it? a very strong reason to deprecate it, since the dangerous behavior does not occur in Debug-mode. So it causes its surprises really late. regards

        1 Reply Last reply
        0
        Reply
        • Reply as topic
        Log in to reply
        • Oldest to Newest
        • Newest to Oldest
        • Most Votes


        • Login

        • Don't have an account? Register

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • World
        • Users
        • Groups