C # Asynchronous call without EndInvoke?

As an example, take the following classes.

public class A { // ... void Foo(S myStruct){...} } public class B { public A test; // ... void Bar() { S myStruct = new S(); test.Foo(myStruct); } } 

Now I want the test.Foo invocation method (myStruct) to be an asynchronous invocation ("fire-and-forget"). The bar method should be back as soon as possible. Documentation around delegates, BeginInvoke, EndInvoke, ThreadPool, etc. Doesn't help me find a solution.

Is this a valid solution?

  // Is using the `EndInvoke` method as the callback delegate valid? foo.BeginInvoke(myStruct, foo.EndInvoke, null); 
+9
c # asynchronous delegates action
Sep 20 2018-11-22T00:
source share
4 answers

You do not need to call EndInvoke ; without naming it simply means:

  • You will not get the return value from the method.
  • Any exceptions that occur during the execution of the method will simply disappear.

It sounds like you want to "burn out and forget", so the easiest way to do this is to use an anonymous delegate, for example:

 var del = new Action(foo.Bar); del.BeginInvoke(iar => { try { del.EndInvoke(iar); } catch (Exception ex) { // Log the message? } }, null); 

Here's what happens when this code is executed:

  • A new thread is allocated (simply) to the delegate.
  • The stream specifies the del delegate and anonymous delegate ( iar => ... ).
  • The thread does del .
  • When a completion is performed (or an exception occurs), the result or exception is saved and an anonymous delegate is executed.
  • Inside an anonymous delegate, when EndInvoke is called, the result from the method is either returned or an exception is thrown (if it happened).

Please note that the above example is very different from:

 // This is pointless and is still, essentially, synchronous. del.EndInvoke(del.BeginInvoke(null, null)); 

Edit: You should always call End* . I have never met a script when it was not caused by a problem, but this is a detailed implementation and relies on undocumented behavior.

Finally, your solution will crash the process if an exception is thrown, you can just pass null as a delegate if you don't care about the exception ( del.BeginInvoke(myStruct, null, null); ). So, as the final example you are looking for is probably:

 public class A { // ... void Foo(S myStruct){...} void FooAsync(S myStruct) { var del = new Action<S>(Foo); del.BeginInvoke(myStruct, SuppressException, del); } static void SuppressException(IAsyncResult ar) { try { ((Action<S>)ar.AsyncState).EndInvoke(ar); } catch { // TODO: Log } } } 
+11
Sep 22 '11 at 8:16
source share

I would say your best option is to use ThreadPool :

 void bar() { ThreadPool.QueueUserWorkItem(o=> { S myStruct = new S(); test.foo(myStruct); }); } 

This will stop the fragment for a single thread. Now you also need to be careful about something else: if you have multiple threads accessing the same instance of A , and this instance modifies the variable, you must make sure that you are correctly synchronizing the variable.

 public class A { private double sum; private volatile bool running; private readonly object sync; public A() { sum = 0.0; running = true; sync = new object(); } public void foo(S myStruct) { // You need to synchronize the whole block because you can get a race // condition (ie running can be set to false after you've checked // the flag and then you would be adding the sum when you're not // supposed to be). lock(sync) { if(running) { sum+=myStruct.Value; } } } public void stop() { // you don't need to synchronize here since the flag is volatile running = false; } } 
+2
Sep 21 2018-11-11T00:
source share

You can use the described callback model @ What is AsyncCallback?

That way your EndInvoke will not be in bar (), but in a separate callback method.

In this example, EndRead (the corresponding EndInvoke is in the callback method called CompleteRead, and not the calling TestCallbackAPM method corresponding to bar)

+1
Sep 22 2018-11-11T00:
source share

This is an option:

 ThreadPool.QueueUserWorkItem(bcl => { var bcList = (List<BarcodeColumn>)bcl; IAsyncResult iftAR = this.dataGridView1.BeginInvoke((MethodInvoker)delegate { int x = this.dataGridView1.Rows[0].Cells.Count - 1; for (int i = 0; i < this.dataGridView1.Rows.Count - 1; i++) { try { string imgPath = bcList[i].GifPath; Image bmpImage = Image.FromFile(imgPath); this.dataGridView1.Rows[i].Cells[x].Value =bmpImage; } catch (Exception) { continue; } } }); while (!iftAR.IsCompleted) { /* wait this*/ } }, barcodeList); 
0
Mar 21 '13 at 8:46
source share



All Articles