MagnusStalberg

Hi,
Is AsyncOperation.PostOperationCompleted guaranteed to post the message to the thread that was requesting the Async method I'm using a STA.

e.g.
I'm using the PrimeNumberCalculator example from MSDN, spawns a new thread (STA), creates a .Net message loop, in the thread I hookup the CalculatePrimeCompleted event and makes a call to CalculatePrimeAsync(...).
What happens is that the
CalculatePrimeCompleted event is sent to another thread than the one that I hooked it up on, I was under the impression that the AsyncOperation.PostOperationCompleted should marshal the call back to the thread that did the actual call (CalculatePrimeAsync).

MSDN help states "
The AsyncOperation object will ensure that your delegate is invoked on the thread or context appropriate for the application model." what does that mean

- Magnus


Re: Common Language Runtime AsyncOperation.PostOperationCompleted posts to the wrong thread

nobugz

How do you know it is running on the wrong thread Did you get an IllegalOperationException





Re: Common Language Runtime AsyncOperation.PostOperationCompleted posts to the wrong thread

MagnusStalberg

Hi, no I did not get the IllegalOperationException exception, but lets say that need to update some UI property when the callback/event arrived and the threadID is not the same as the threadID were the UI component was created one, then there is a problem.
This is what happens in my case. But only if I have created a new thread from were I run this code.

E.g.
I start a WinformsApplication, from within that I create a new thread that I use to create/call the Async method. I thought that I was going to get the callback on the same thread that I created not a another one.

- Magnus




Re: Common Language Runtime AsyncOperation.PostOperationCompleted posts to the wrong thread

nobugz

You'll get the callback on the same thread that called AsyncOperationManager.CreateOperation() and the worker delegate's BeginInvoke() method. That would be your "new thread", not the UI thread so you can't touch any controls or forms. Just don't create a thread. BackgroundWorker is easier to use. If this is not accurate, you'd better post some code.





Re: Common Language Runtime AsyncOperation.PostOperationCompleted posts to the wrong thread

MagnusStalberg

That is what I thought, but the callback comes on a different thread. I can attach a small sample the will illustrate the problem I can not post the "real" code because that is in an very large system.

But the code will show the problem that I have, just run the code in the debugger and check the output.

static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}

public partial class Form1 : Form
{
Thread thread;

public Form1()
{
InitializeComponent();

thread = new Thread(new ThreadStart(ThreadProc));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}

public void ThreadProc()
{
Calculator calculator = new Calculator();
Application.Run();
}
}

class Calculator
{
private PrimeNumberCalculator calculator;
private Guid taskId;

public Calculator()
{
calculator = new PrimeNumberCalculator();
calculator.CalculatePrimeCompleted += new CalculatePrimeCompletedEventHandler(calculator_CalculatePrimeCompleted);
taskId = Guid.NewGuid();

Debug.WriteLine("Calculator");
Debug.WriteLine("=======================");
Debug.WriteLine("ManagedThreadId: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
// This will call the AsyncOperationManager.CreateOperation() on the correct thread
calculator.CalculatePrimeAsync(235, taskId);
}

void calculator_CalculatePrimeCompleted(object sender, CalculatePrimeCompletedEventArgs e)
{
if (!(e.UserState is Guid))
return;
if ((Guid)e.UserState != taskId)
return;
Debug.WriteLine("CalculatePrimeCompleted");
Debug.WriteLine("=======================");
Debug.WriteLine("ManagedThreadId: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
Debug.WriteLine(e.IsPrime);
}
}

#region PrimeNumberCalculator Implementation

public delegate void ProgressChangedEventHandler(
ProgressChangedEventArgs e);

public delegate void CalculatePrimeCompletedEventHandler(
object sender,
CalculatePrimeCompletedEventArgs e);

// This class implements the Asynchronous Pattern for Components.
// It asynchronously computes whether a number is prime or
// composite (not prime).
public class PrimeNumberCalculator : Component
{

private delegate void WorkerEventHandler(
int numberToCheck,
AsyncOperation asyncOp,
SendOrPostCallback completionMethodDelegate);

private SendOrPostCallback onProgressReportDelegate;
private SendOrPostCallback onCompletedDelegate;
private SendOrPostCallback completionMethodDelegate;

private WorkerEventHandler workerDelegate;

private HybridDictionary userStateToLifetime =
new HybridDictionary();

private System.ComponentModel.Container components = null;

/////////////////////////////////////////////////////////////
#region Public events

public event ProgressChangedEventHandler ProgressChanged;
public event CalculatePrimeCompletedEventHandler CalculatePrimeCompleted;

#endregion

/////////////////////////////////////////////////////////////
#region Construction and destruction

public PrimeNumberCalculator(IContainer container)
{
container.Add(this);
InitializeComponent();

InitializeDelegates();
}

public PrimeNumberCalculator()
{
InitializeComponent();

InitializeDelegates();
}

protected virtual void InitializeDelegates()
{
onProgressReportDelegate =
new SendOrPostCallback(ReportProgress);
onCompletedDelegate =
new SendOrPostCallback(CalculateCompleted);
completionMethodDelegate =
new SendOrPostCallback(CompletionMethod);
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}

#endregion // Construction and destruction

/////////////////////////////////////////////////////////////
///
#region Implementation

// This method starts the asynchronous calculation.
// First, it checks the supplied task ID for uniqueness.
// If taskId is unique, it creates a new WorkerEventHandler
// and calls its BeginInvoke method to start the calculation.
public virtual void CalculatePrimeAsync(
int numberToTest,
object taskId)
{
Debug.WriteLine("CalculatePrimeAsync: ManagedThreadId: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
// Create an AsyncOperation for taskId.
AsyncOperation asyncOp =
AsyncOperationManager.CreateOperation(taskId);

// Multiple threads will access the task dictionary,
// so it must be locked to serialize access.
lock (userStateToLifetime.SyncRoot)
{
if (userStateToLifetime.Contains(taskId))
{
throw new ArgumentException(
"Task ID parameter must be unique",
"taskId");
}

userStateToLifetime[taskId] = asyncOp;
}

// Start the asynchronous operation.
workerDelegate = new WorkerEventHandler(CalculateWorker);
workerDelegate.BeginInvoke(
numberToTest,
asyncOp,
completionMethodDelegate,
null,
null);
}

// This method cancels a pending asynchronous operation.
public void CancelAsync(object taskId)
{
lock (userStateToLifetime.SyncRoot)
{
object obj = userStateToLifetime[taskId];
if (obj != null)
{
AsyncOperation asyncOp = obj as AsyncOperation;

int numberToTest = 0;
int firstDivisor = 1;
bool isPrime = false;
Exception exception = null;
bool canceled = true;

CalculatePrimeCompletedEventArgs e =
new CalculatePrimeCompletedEventArgs(
numberToTest,
firstDivisor,
isPrime,
exception,
canceled,
asyncOp.UserSuppliedState);

// The asyncOp object is responsible for
// marshaling the call to the proper
// thread or context.
asyncOp.PostOperationCompleted(
onCompletedDelegate,
e);
}
}
}

// This method performs the actual prime number computation.
// It is executed on the worker thread.
private void CalculateWorker(
int numberToTest,
AsyncOperation asyncOp,
SendOrPostCallback completionMethodDelegate)
{
Debug.WriteLine("CalculateWorker: ManagedThreadId: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
bool isPrime = false;
int firstDivisor = 1;
Exception e = null;

try
{
// Find all the prime numbers up to
// the square root of numberToTest.
ArrayList primes = BuildPrimeNumberList(
numberToTest,
asyncOp);

// Now we have a list of primes less than
// numberToTest.
isPrime = IsPrime(
primes,
numberToTest,
out firstDivisor);
}
catch (Exception ex)
{
e = ex;
}

CalculatePrimeState calcState = new CalculatePrimeState(
numberToTest,
firstDivisor,
isPrime,
e,
asyncOp);

completionMethodDelegate(calcState);
}

// This method computes the list of prime numbers used by the
// IsPrime method.
private ArrayList BuildPrimeNumberList(
int numberToTest,
AsyncOperation asyncOp)
{
ProgressChangedEventArgs e = null;
ArrayList primes = new ArrayList();
int firstDivisor;
int n = 5;

// Add the first prime numbers.
primes.Add(2);
primes.Add(3);

// Do the work.
while (n < numberToTest)
{
if (IsPrime(primes, n, out firstDivisor))
{
// Report to the client that a prime was found.
e = new CalculatePrimeProgressChangedEventArgs(
n,
(int)((float)n / (float)numberToTest * 100),
asyncOp.UserSuppliedState);

asyncOp.Post(this.onProgressReportDelegate, e);

primes.Add(n);

// Yield the rest of this time slice.
Thread.Sleep(0);
}

// Skip even numbers.
n += 2;

// No prime to report, so just use a
// ProgressChangedEventArgs object.
e = new ProgressChangedEventArgs(
(int)((float)n / (float)numberToTest * 100),
asyncOp.UserSuppliedState);

asyncOp.Post(this.onProgressReportDelegate, e);
}

return primes;
}

// This method tests n for primality against the list of
// prime numbers contained in the primes parameter.
private bool IsPrime(
ArrayList primes,
int n,
out int firstDivisor)
{
bool foundDivisor = false;
bool exceedsSquareRoot = false;

int i = 0;
int divisor = 0;
firstDivisor = 1;

// Stop the search if:
// there are no more primes in the list,
// there is a divisor of n in the list, or
// there is a prime that is larger than
// the square root of n.
while (
(i < primes.Count) &&
!foundDivisor &&
!exceedsSquareRoot)
{
// The divisor variable will be the smallest
// prime number not yet tried.
divisor = (int)primes[i++];

// Determine whether the divisor is greater
// than the square root of n.
if (divisor * divisor > n)
{
exceedsSquareRoot = true;
}
// Determine whether the divisor is a factor of n.
else if (n % divisor == 0)
{
firstDivisor = divisor;
foundDivisor = true;
}
}

return !foundDivisor;
}

// This method is invoked via the AsyncOperation object,
// so it is guaranteed to be executed on the correct thread.
private void CalculateCompleted(object operationState)
{
CalculatePrimeCompletedEventArgs e =
operationState as CalculatePrimeCompletedEventArgs;

OnCalculatePrimeCompleted(e);
}

// This method is invoked via the AsyncOperation object,
// so it is guaranteed to be executed on the correct thread.
private void ReportProgress(object state)
{
ProgressChangedEventArgs e =
state as ProgressChangedEventArgs;

OnProgressChanged(e);
}

protected void OnCalculatePrimeCompleted(
CalculatePrimeCompletedEventArgs e)
{
Debug.WriteLine("OnCalculatePrimeCompleted: ManagedThreadId: " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString());
if (CalculatePrimeCompleted != null)
{
CalculatePrimeCompleted(this, e);
}
}

protected void OnProgressChanged(ProgressChangedEventArgs e)
{
if (ProgressChanged != null)
{
ProgressChanged(e);
}
}

// This is the method that the underlying, free-threaded
// asynchronous behavior will invoke. This will happen on
// an arbitrary thread.
private void CompletionMethod(object calculateState)
{
CalculatePrimeState calcState =
calculateState as CalculatePrimeState;

AsyncOperation asyncOp = calcState.asyncOp;

int numberToTest = calcState.numberToTest;
int firstDivisor = calcState.firstDivisor;
bool isPrime = calcState.isPrime;
Exception exception = calcState.ex;
bool canceled = false;

CalculatePrimeCompletedEventArgs e =
new CalculatePrimeCompletedEventArgs(
numberToTest,
firstDivisor,
isPrime,
exception,
canceled,
asyncOp.UserSuppliedState);

// In this case, don't allow cancellation, as the method
// is about to raise the completed event.
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}

// The asyncOp object is responsible for marshaling
// the call.
asyncOp.PostOperationCompleted(onCompletedDelegate, e);

// Note that after the call to OperationCompleted,
// asyncOp is no longer usable, and any attempt to use it
// will cause an exception to be thrown.
}


#endregion

/////////////////////////////////////////////////////////////
#region Component Designer generated code

private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}

#endregion

}

internal class CalculatePrimeState
{
public int numberToTest = 0;
public int firstDivisor = 1;
public bool isPrime = false;
public AsyncOperation asyncOp = null;
public Exception ex = null;

public CalculatePrimeState(
int numberToTest,
int firstDivisor,
bool isPrime,
Exception ex,
AsyncOperation asyncOp)
{
this.numberToTest = numberToTest;
this.firstDivisor = firstDivisor;
this.isPrime = isPrime;
this.ex = ex;
this.asyncOp = asyncOp;
}
}

public class CalculatePrimeProgressChangedEventArgs :
ProgressChangedEventArgs
{
private int latestPrimeNumberValue = 1;

public CalculatePrimeProgressChangedEventArgs(
int latestPrime,
int progressPercentage,
object userToken)
: base(progressPercentage, userToken)
{
this.latestPrimeNumberValue = latestPrime;
}

public int LatestPrimeNumber
{
get
{
return latestPrimeNumberValue;
}
}
}

public class CalculatePrimeCompletedEventArgs :
AsyncCompletedEventArgs
{
private int numberToTestValue = 0;
private int firstDivisorValue = 1;
private bool isPrimeValue;

public CalculatePrimeCompletedEventArgs(
int numberToTest,
int firstDivisor,
bool isPrime,
Exception e,
bool canceled,
object state)
: base(e, canceled, state)
{
this.numberToTestValue = numberToTest;
this.firstDivisorValue = firstDivisor;
this.isPrimeValue = isPrime;
}

public int NumberToTest
{
get
{
// Raise an exception if the operation failed or
// was canceled.
RaiseExceptionIfNecessary();

// If the operation was successful, return the
// property value.
return numberToTestValue;
}
}

public int FirstDivisor
{
get
{
// Raise an exception if the operation failed or
// was canceled.
RaiseExceptionIfNecessary();

// If the operation was successful, return the
// property value.
return firstDivisorValue;
}
}

public bool IsPrime
{
get
{
// Raise an exception if the operation failed or
// was canceled.
RaiseExceptionIfNecessary();

// If the operation was successful, return the
// property value.
return isPrimeValue;
}
}
}


#endregion




Re: Common Language Runtime AsyncOperation.PostOperationCompleted posts to the wrong thread

nobugz

Your problem is caused by the AsyncOperation.SynchronizationContext property. The default instance uses free threading so the callback delegates are called on a thread pool thread. I fixed it like this:

SynchronizationContext ctx = AsyncOperationManager.SynchronizationContext;
AsyncOperationManager.SynchronizationContext = new WindowsFormsSynchronizationContext();
AsyncOperation asyncOp =
AsyncOperationManager.CreateOperation(taskId);
AsyncOperationManager.SynchronizationContext = ctx;

That's not a proper fix though and is not going to work for you in .NET 1.1. Windows Forms creates a new SynchronizationContext when the message loop starts running, ensuring that AsyncOperation callbacks are synchronized to the UI thread with help from the message loop. Under the hood, WindowsFormsSynchronizationContext uses Control.BeginInvoke().

Your code has two problems: you create the AsyncOperation too soon, before WF had a chance to create the context. Use the Load event to avoid this. And you create the AsyncOperation in a thread. Lose the thread and solve your problem.

This is all relevant for .NET 2.0. Not sure how .NET 1.1 works, it doesn't have the WindowsFormsSynchronizationContext class.





Re: Common Language Runtime AsyncOperation.PostOperationCompleted posts to the wrong thread

MagnusStalberg

Hi, thanks for the information.

Two things, we cannot lose the thread, and it is not sure that the client that uses this ¡°calculator¡± class is a WindowsForms application; it might be a WPF as well.

This is how the application works:


We have an application that is capable of hosting controls (small applications), the controls might be written in MFC, ATL, Windows Forms, WPF. And the hosting application can open several controls in overlap windows and all the overlap windows get its own thread with Message Pump/Loop.


And I am trying to write a .Net Library (framework) that is asynchronous that can be used either from a WindowsForms control or a WPF control. And I want to use the Event-based synchronize pattern because then the one that implements the framework needs to do it asynchronous

I hope this clarifies the problem a bit more.