public void Post_ToCopiedDispatcher_IsAsynchronous()
        {
            SynchronizationContext actionDispatcherSyncContext = null;

            using (ManualResetEvent completed = new ManualResetEvent(false))
            using (ManualResetEvent wait = new ManualResetEvent(false))
            using (ActionThread thread1 = new ActionThread())
            using (ActionThread thread2 = new ActionThread())
            {
                thread1.Start();
                thread2.Start();

                // Capture the second thread's SynchronizationContext and signal this thread when it's captured.
                actionDispatcherSyncContext = thread2.DoGet(() => { return SynchronizationContext.Current.CreateCopy(); });

                // Have the first thread do an synchronous Post to the second thread and then trigger the "completed" event.
                // The action queued to the second thread will wait for the "wait" event.

                thread1.Do(() =>
                {
                    actionDispatcherSyncContext.Post((state) => { wait.WaitOne(); }, null);
                    completed.Set();
                });

                bool completedSignalled = completed.WaitOne(100);
                Assert.IsTrue(completedSignalled, "ActionDispatcherSynchronizationContext.Post is not asynchronous");

                wait.Set();
            }
        }
        public void InvalidBoundSyncedFunc_Invoked_DoesSync()
        {
            bool sawSync = false;

            using (CallbackContext context = new CallbackContext())
                using (ActionThread thread = new ActionThread())
                {
                    thread.Start();

                    // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                    SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                    var syncContext = new Util.LoggingSynchronizationContext(actionThreadSyncContext)
                    {
                        OnPost = () => { sawSync = true; },
                        OnSend = () => { sawSync = true; }
                    };

                    var action = context.Bind(() => { return(13); }, syncContext, false);
                    context.Reset();
                    int result = action();

                    Assert.IsTrue(sawSync, "Context did not use SyncContext for sync");
                }
        }
        public void SyncedActionWithFourArguments_Invoked_ReceivesParameters()
        {
            int arg1 = 0;
            int arg2 = 0;
            int arg3 = 0;
            int arg4 = 0;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                Action <int, int, int, int> action = thread.DoGet(() =>
                {
                    return(Sync.SynchronizeAction((int a1, int a2, int a3, int a4) => { arg1 = a1; arg2 = a2; arg3 = a3; arg4 = a4; }));
                });

                action(13, 17, 19, 23);
                thread.Join();

                Assert.AreEqual(13, arg1, "Action did not receive parameter");
                Assert.AreEqual(17, arg2, "Action did not receive parameter");
                Assert.AreEqual(19, arg3, "Action did not receive parameter");
                Assert.AreEqual(23, arg4, "Action did not receive parameter");
            }
        }
        public void Send_ToCopiedDispatcher_IsSynchronous()
        {
            SynchronizationContext actionDispatcherSyncContext = null;

            using (ManualResetEvent completed = new ManualResetEvent(false))
                using (ManualResetEvent wait = new ManualResetEvent(false))
                    using (ActionThread thread1 = new ActionThread())
                        using (ActionThread thread2 = new ActionThread())
                        {
                            thread1.Start();
                            thread2.Start();

                            // Capture the second thread's SynchronizationContext and signal this thread when it's captured.
                            actionDispatcherSyncContext = thread2.DoGet(() => { return(SynchronizationContext.Current.CreateCopy()); });

                            // Have the first thread do a synchronous Send to the second thread and then trigger the "completed" event.
                            // The action queued to the second thread will wait for the "wait" event.

                            thread1.Do(() =>
                            {
                                actionDispatcherSyncContext.Send((state) => { wait.WaitOne(); }, null);
                                completed.Set();
                            });

                            bool completedSignalled = completed.WaitOne(100);
                            Assert.IsFalse(completedSignalled, "ActionDispatcherSynchronizationContext.Send is not synchronous");

                            wait.Set();
                        }
        }
        public void BoundAsyncAction_Invoked_UsesSyncContext()
        {
            bool sawSync = false;

            using (CallbackContext context = new CallbackContext())
                using (ActionThread thread = new ActionThread())
                {
                    thread.Start();

                    // Capture the thread's SynchronizationContext
                    SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                    var syncContext = new Util.LoggingSynchronizationContext(actionThreadSyncContext)
                    {
                        OnPost = () => { sawSync = true; },
                        OnSend = () => { sawSync = true; }
                    };

                    var action = context.AsyncBind(() => { }, syncContext, false);
                    action();
                    thread.Join();

                    Assert.IsTrue(sawSync, "Context did not use SyncContext for sync");
                }
        }
        public void SyncFunc_QueuedAfterStart_PreservesReturnValue()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                object obj = thread.DoGet(() => { return(new object()); });
                Assert.IsNotNull(obj, "ActionThread did not return result");
            }
        }
 public void ThreadPoolGSO_FromChildThread_DoesRequireInvoke()
 {
     using (ScopedSynchronizationContext x = new ScopedSynchronizationContext(new SynchronizationContext()))
         using (ActionThread thread = new ActionThread())
         {
             GenericSynchronizingObject test = new GenericSynchronizingObject();
             thread.Start();
             bool invokeRequired = thread.DoGet(() => test.InvokeRequired);
             Assert.IsTrue(invokeRequired, "ThreadPool GenericSynchronizingObject does not require invoke from within a child thread");
         }
 }
        public void ActionThreadGSO_OutsideActionThread_DoesRequireInvoke()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                Assert.IsTrue(test.InvokeRequired, "GenericSynchronizingObject does not require invoke for ActionThread");
            }
        }
        public void ActionThreadGSO_WithinActionThread_DoesNotRequireInvoke()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture InvokeRequired from the ActionThread's context
                bool nestedInvokeRequired = thread.DoGet(() => { return(new GenericSynchronizingObject().InvokeRequired); });

                Assert.IsFalse(nestedInvokeRequired, "GenericSynchronizingObject does require invoke within ActionThread");
            }
        }
        public void ActionThreadGSO_WithinActionThread_DoesNotRequireInvoke()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture InvokeRequired from the ActionThread's context
                bool nestedInvokeRequired = thread.DoGet(() => { return new GenericSynchronizingObject().InvokeRequired; });

                Assert.IsFalse(nestedInvokeRequired, "GenericSynchronizingObject does require invoke within ActionThread");
            }
        }
        public void FailingAction_InvokedThroughActionThreadGSO_ThrowsTargetInvocationException()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                test.Invoke((MethodInvoker)(() => { throw new Exception(); }), null);
            }
        }
        public void ActionThreadGSO_OutsideActionThread_DoesRequireInvoke()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                Assert.IsTrue(test.InvokeRequired, "GenericSynchronizingObject does not require invoke for ActionThread");
            }
        }
        public void SyncFunc_QueuedAfterStart_IsExecutedByThread()
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();
                object obj = thread.DoGet(() => { threadId = Thread.CurrentThread.ManagedThreadId; return(new object()); });

                Assert.AreEqual(thread.ManagedThreadId, threadId, "ActionThread ran in wrong thread context");
            }
        }
        public void AsyncResult_FromBeginInvoke_HasNullAsyncState()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                Assert.IsNull(result.AsyncState, "IAsyncResult.AsyncState is not used and should be null");
            }
        }
        public void AsyncResult_FromBeginInvoke_DidNotCompleteSynchronously()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                Assert.IsFalse(result.CompletedSynchronously, "IAsyncResult.CompletedSynchronously is not used and should be false");
            }
        }
        public void SyncContext_FromInsideAction_IsActionDispatcherSyncContext()
        {
            SynchronizationContext actionThreadSyncContext = null;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                Assert.IsInstanceOfType(actionThreadSyncContext, typeof(ActionDispatcherSynchronizationContext), "ActionThread did not provide an ActionDispatcherSynchronizationContext");
            }
        }
        public void AsyncResultWaitHandle_FromBeginInvoke_IsWaitable()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                IAsyncResult result    = test.BeginInvoke((MethodInvoker)(() => { }), null);
                bool         signalled = result.AsyncWaitHandle.WaitOne(100);
                Assert.IsTrue(signalled, "AsyncWaitHandle should be signalled");
            }
        }
Exemple #18
0
    static void Main()
    {
        using (ActionThread actionThread = new ActionThread())
        {
            actionThread.Start();

            Console.WriteLine("Console thread ID: " + Thread.CurrentThread.ManagedThreadId);

            // Any delegates passed to ActionThread.DoGet are run by that ActionThread (synchronously)
            int actionThreadID = actionThread.DoGet(() => Thread.CurrentThread.ManagedThreadId);

            Console.WriteLine("ActionThread thread ID: " + actionThreadID);
        }
    }
        public void AsyncResult_AfterEndInvoke_ReturnsImmediatelyFromEndInvoke()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                test.EndInvoke(result);
                test.EndInvoke(result);
            }
        }
        public void Action_InvokedThroughActionThreadGSO_RunsOnTheActionThread()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                int actionThreadId = Thread.CurrentThread.ManagedThreadId;
                test.Invoke((MethodInvoker)(() => { actionThreadId = Thread.CurrentThread.ManagedThreadId; }), null);

                Assert.AreEqual(thread.ManagedThreadId, actionThreadId, "GenericSynchronizingObject.Invoke did not synchronize");
            }
        }
        public void Action_InvokedThroughActionThreadGSO_Runs()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                test.Invoke((MethodInvoker)(() => { sawAction = true; }), null);

                Assert.AreEqual(true, sawAction, "GenericSynchronizingObject.Invoke did not execute action");
            }
        }
        public void Action_BeginInvokeThroughActionThreadGSO_RunsOnTheActionThread()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                int actionThreadId = Thread.CurrentThread.ManagedThreadId;
                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { actionThreadId = Thread.CurrentThread.ManagedThreadId; }), null);
                test.EndInvoke(result);

                Assert.AreEqual(thread.ManagedThreadId, actionThreadId, "GenericSynchronizingObject.BeginInvoke did not synchronize");
            }
        }
        public void AsyncResultWaitHandle_FromBeginInvoke_IsPollable()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                while (!result.IsCompleted)
                {
                    Thread.Sleep(20);
                }
            }
        }
        public void Action_InvokedThroughActionThreadGSO_ReceivesParameters()
        {
            object parameter = new object();
            object argument  = null;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                test.Invoke((Action <object>)((arg) => { argument = arg; }), new [] { parameter });

                Assert.AreSame(parameter, argument, "GenericSynchronizingObject.Invoke did not pass parameter");
            }
        }
        public void InvalidBoundSyncedFunc_Invoked_ReturnsDefault()
        {
            using (CallbackContext context = new CallbackContext())
                using (ActionThread thread = new ActionThread())
                {
                    thread.Start();

                    // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                    SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                    var action = context.Bind(() => { return(13); }, actionThreadSyncContext, false);
                    context.Reset();
                    int result = action();

                    Assert.AreEqual(0, result, "Invalid Func returned a non-default value");
                }
        }
        public void Action_BeginInvokeThroughActionThreadGSO_Runs()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { sawAction = true; }), null);
                test.EndInvoke(result);

                Assert.IsTrue(sawAction, "GenericSynchronizingObject.BeginInvoke did not execute action");
            }
        }
        public void SyncContext_FromInsideAction_SendsToSameThread()
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                // Use the SynchronizationContext to give the ActionThread more work to do
                actionThreadSyncContext.Send((state) => { threadId = Thread.CurrentThread.ManagedThreadId; }, null);

                Assert.AreEqual(thread.ManagedThreadId, threadId, "ActionThread ran in wrong thread context");
            }
        }
        public void Action_BeginInvokeThroughActionThreadGSO_Runs()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return(new GenericSynchronizingObject()); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { sawAction = true; }), null);
                test.EndInvoke(result);

                Assert.IsTrue(sawAction, "GenericSynchronizingObject.BeginInvoke did not execute action");
            }
        }
        public void ActionWithThreeArguments_AfterSync_HasNotRun()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                Action<int, int, int> action = thread.DoGet(() =>
                {
                    return Sync.SynchronizeAction((int a1, int a2, int a3) => { sawAction = true; });
                });

                // The action should be run in the context of the ActionThread
                Assert.IsFalse(sawAction, "Action should not have run already");
            }
        }
        public void WaitOrTimerCallback_AfterSync_HasNotRun()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                WaitOrTimerCallback action = thread.DoGet(() =>
                {
                    return(Sync.SynchronizeWaitOrTimerCallback((a1, a2) => { sawAction = true; }));
                });

                // The action should be run in the context of the ActionThread
                Assert.IsFalse(sawAction, "Action should not have run already");
            }
        }
        public void ActionWithOneArgument_AfterSync_HasNotRun()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                Action <int> action = thread.DoGet(() =>
                {
                    return(Sync.SynchronizeAction((int a1) => { sawAction = true; }));
                });

                // The action should be run in the context of the ActionThread
                Assert.IsFalse(sawAction, "Action should not have run already");
            }
        }
        public void BoundSyncedFunc_Invoked_ExecutesSynchronized()
        {
            int sawActionThread = Thread.CurrentThread.ManagedThreadId;

            using (CallbackContext context = new CallbackContext())
                using (ActionThread thread = new ActionThread())
                {
                    thread.Start();

                    // Capture the thread's SynchronizationContext
                    SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                    var action = context.Bind(() => { sawActionThread = Thread.CurrentThread.ManagedThreadId; return(13); }, actionThreadSyncContext);
                    int result = action();

                    Assert.AreEqual(thread.ManagedThreadId, sawActionThread, "Bound action was not synchronized");
                }
        }
        public void InvalidBoundSyncedFunc_Invoked_DoesNotExecute()
        {
            int sawActionThread = Thread.CurrentThread.ManagedThreadId;

            using (CallbackContext context = new CallbackContext())
                using (ActionThread thread = new ActionThread())
                {
                    thread.Start();

                    // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                    SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return(SynchronizationContext.Current); });

                    var action = context.Bind(() => { sawActionThread = Thread.CurrentThread.ManagedThreadId; return(13); }, actionThreadSyncContext, false);
                    context.Reset();
                    int result = action();

                    Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, sawActionThread, "Invalid action should not run");
                }
        }
        public void SyncedActionWithOneArgument_Invoked_ReceivesParameters()
        {
            int arg1 = 0;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                Action <int> action = thread.DoGet(() =>
                {
                    return(Sync.SynchronizeAction((int a1) => { arg1 = a1; }));
                });

                action(13);
                thread.Join();

                Assert.AreEqual(13, arg1, "Action did not receive parameter");
            }
        }
        public void SyncedWaitOrTimerCallback_Invoked_RunsSynchronized()
        {
            int actionThreadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                WaitOrTimerCallback action = thread.DoGet(() =>
                {
                    return(Sync.SynchronizeWaitOrTimerCallback((a1, a2) => { actionThreadId = Thread.CurrentThread.ManagedThreadId; }));
                });

                // The action should be run in the context of the ActionThread
                action(null, false);
                thread.Join();

                Assert.AreEqual(thread.ManagedThreadId, actionThreadId, "Action did not run synchronized");
            }
        }
        public void SyncedActionWithOneArgument_Invoked_RunsSynchronized()
        {
            int actionThreadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                Action <int> action = thread.DoGet(() =>
                {
                    return(Sync.SynchronizeAction((int a1) => { actionThreadId = Thread.CurrentThread.ManagedThreadId; }));
                });

                // The action should be run in the context of the ActionThread
                action(13);
                thread.Join();

                Assert.AreEqual(thread.ManagedThreadId, actionThreadId, "Action did not run synchronized");
            }
        }
        public void BoundAsyncAction_Invoked_DecrementsSyncContextOperationCount()
        {
            bool sawOperationCompleted = false;

            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var syncContext = new LoggingSynchronizationContext(actionThreadSyncContext)
                {
                    OnOperationCompleted = () => { sawOperationCompleted = true; }
                };

                var action = context.AsyncBind(() => { }, syncContext, false);
                action();
                thread.Join();

                Assert.IsFalse(sawOperationCompleted, "Context decremented operation count");
            }
        }
        public void AsyncResult_AfterWait_ReturnsImmediatelyFromEndInvoke()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                result.AsyncWaitHandle.WaitOne(100);
                test.EndInvoke(result);
            }
        }
        public void AsyncResult_FromBeginInvoke_DidNotCompleteSynchronously()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                Assert.IsFalse(result.CompletedSynchronously, "IAsyncResult.CompletedSynchronously is not used and should be false");
            }
        }
        public void AsyncResult_FromBeginInvoke_HasNullAsyncState()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                Assert.IsNull(result.AsyncState, "IAsyncResult.AsyncState is not used and should be null");
            }
        }
        public void FailingAction_InvokedThroughActionThreadGSO_PreservesExceptionAsInnerException()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                Exception errorToThrow = new MyException();
                Exception innerErrorCaught = null;
                try
                {
                    test.Invoke((MethodInvoker)(() => { throw errorToThrow; }), null);
                }
                catch (TargetInvocationException ex)
                {
                    innerErrorCaught = ex.InnerException;
                }

                Assert.AreSame(errorToThrow, innerErrorCaught, "Exception not preserved");
            }
        }
        public void InvalidBoundSyncedFunc_Invoked_ReturnsDefault()
        {
            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var action = context.Bind(() => { return 13; }, actionThreadSyncContext, false);
                context.Reset();
                int result = action();

                Assert.AreEqual(0, result, "Invalid Func returned a non-default value");
            }
        }
        public void WaitOrTimerCallback_AfterSync_HasNotRun()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                WaitOrTimerCallback action = thread.DoGet(() =>
                {
                    return Sync.SynchronizeWaitOrTimerCallback((a1, a2) => { sawAction = true; });
                });

                // The action should be run in the context of the ActionThread
                Assert.IsFalse(sawAction, "Action should not have run already");
            }
        }
        public void AsyncResultWaitHandle_FromBeginInvoke_IsPollable()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                while (!result.IsCompleted)
                {
                    Thread.Sleep(20);
                }
            }
        }
        public void SyncContext_FromInsideAction_SendsToSameThread()
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                // Use the SynchronizationContext to give the ActionThread more work to do
                actionThreadSyncContext.Send((state) => { threadId = Thread.CurrentThread.ManagedThreadId; }, null);

                Assert.AreEqual(thread.ManagedThreadId, threadId, "ActionThread ran in wrong thread context");
            }
        }
        public void SyncedWaitOrTimerCallback_Invoked_RunsSynchronized()
        {
            int actionThreadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                WaitOrTimerCallback action = thread.DoGet(() =>
                {
                    return Sync.SynchronizeWaitOrTimerCallback((a1, a2) => { actionThreadId = Thread.CurrentThread.ManagedThreadId; });
                });

                // The action should be run in the context of the ActionThread
                action(null, false);
                thread.Join();

                Assert.AreEqual(thread.ManagedThreadId, actionThreadId, "Action did not run synchronized");
            }
        }
        public void BoundSyncedAction_Invoked_UsesSyncContext()
        {
            bool sawSync = false;

            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var syncContext = new LoggingSynchronizationContext(actionThreadSyncContext)
                {
                    OnPost = () => { sawSync = true; },
                    OnSend = () => { sawSync = true; }
                };

                var action = context.Bind(() => { }, syncContext, false);
                action();

                Assert.IsTrue(sawSync, "Context did not use SyncContext for sync");
            }
        }
        public void BoundSyncedFunc_Invoked_IncrementsSyncContextOperationCount()
        {
            bool sawOperationStarted = false;

            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var syncContext = new LoggingSynchronizationContext(actionThreadSyncContext)
                {
                    OnOperationStarted = () => { sawOperationStarted = true; }
                };

                var action = context.Bind(() => { return 13; }, syncContext, false);
                int result = action();

                Assert.IsFalse(sawOperationStarted, "Context incremented operation count");
            }
        }
        public void BoundAsyncAction_Invoked_ExecutesSynchronized()
        {
            int sawActionThread = Thread.CurrentThread.ManagedThreadId;

            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var action = context.AsyncBind(() => { sawActionThread = Thread.CurrentThread.ManagedThreadId; }, actionThreadSyncContext);
                action();
                thread.Join();

                Assert.AreEqual(thread.ManagedThreadId, sawActionThread, "Bound action was not synchronized");
            }
        }
        public void InvalidBoundSyncedFunc_Invoked_DoesNotExecute()
        {
            int sawActionThread = Thread.CurrentThread.ManagedThreadId;

            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var action = context.Bind(() => { sawActionThread = Thread.CurrentThread.ManagedThreadId; return 13; }, actionThreadSyncContext, false);
                context.Reset();
                int result = action();

                Assert.AreEqual(Thread.CurrentThread.ManagedThreadId, sawActionThread, "Invalid action should not run");
            }
        }
        public void AsyncResultWaitHandle_FromBeginInvoke_IsWaitable()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                ISynchronizeInvoke test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((MethodInvoker)(() => { }), null);
                bool signalled = result.AsyncWaitHandle.WaitOne(100);
                Assert.IsTrue(signalled, "AsyncWaitHandle should be signalled");
            }
        }
        public void SyncContext_FromInsideAction_IsActionDispatcherSyncContext()
        {
            SynchronizationContext actionThreadSyncContext = null;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                Assert.IsInstanceOfType(actionThreadSyncContext, typeof(ActionDispatcherSynchronizationContext), "ActionThread did not provide an ActionDispatcherSynchronizationContext");
            }
        }
        public void Send_IsSynchronous()
        {
            SynchronizationContext actionDispatcherSyncContext = null;

            using (ManualResetEvent completed = new ManualResetEvent(false))
            using (ManualResetEvent wait = new ManualResetEvent(false))
            using (ActionThread thread1 = new ActionThread())
            using (ActionThread thread2 = new ActionThread())
            {
                thread1.Start();
                thread2.Start();

                // Capture the second thread's SynchronizationContext.
                actionDispatcherSyncContext = thread2.DoGet(() => { return SynchronizationContext.Current; });

                // Have the first thread do a synchronous Send to the second thread and then trigger the "completed" event.
                // The action queued to the second thread will wait for the "wait" event.

                thread1.Do(() =>
                    {
                        actionDispatcherSyncContext.Send((state) => { wait.WaitOne(); }, null);
                        completed.Set();
                    });

                bool completedSignalled = completed.WaitOne(100);
                Assert.IsFalse(completedSignalled, "ActionDispatcherSynchronizationContext.Send is not synchronous");

                wait.Set();
            }
        }
        public void Action_BeginInvokeThroughGSO_ReceivesParameters()
        {
            object parameter = new object();
            object argument = null;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                IAsyncResult result = test.BeginInvoke((Action<object>)((arg) => { argument = arg; }), new [] { parameter });
                test.EndInvoke(result);

                Assert.AreSame(parameter, argument, "GenericSynchronizingObject.BeginInvoke did not pass parameter");
            }
        }
        public void Action_InvokedThroughActionThreadGSO_Runs()
        {
            bool sawAction = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                test.Invoke((MethodInvoker)(() => { sawAction = true; }), null);

                Assert.AreEqual(true, sawAction, "GenericSynchronizingObject.Invoke did not execute action");
            }
        }
        public void FailingAction_InvokedThroughActionThreadGSO_ThrowsTargetInvocationException()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture GenericSynchronizingObject
                GenericSynchronizingObject test = thread.DoGet(() => { return new GenericSynchronizingObject(); });

                test.Invoke((MethodInvoker)(() => { throw new Exception(); }), null);
            }
        }
        public void SyncFunc_QueuedAfterStart_IsExecutedByThread()
        {
            int threadId = Thread.CurrentThread.ManagedThreadId;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();
                object obj = thread.DoGet(() => { threadId = Thread.CurrentThread.ManagedThreadId; return new object(); });

                Assert.AreEqual(thread.ManagedThreadId, threadId, "ActionThread ran in wrong thread context");
            }
        }
        public void InvalidBoundSyncedFunc_Invoked_DoesSync()
        {
            bool sawSync = false;

            using (CallbackContext context = new CallbackContext())
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Capture the thread's SynchronizationContext and signal this thread when it's captured.
                SynchronizationContext actionThreadSyncContext = thread.DoGet(() => { return SynchronizationContext.Current; });

                var syncContext = new LoggingSynchronizationContext(actionThreadSyncContext)
                {
                    OnPost = () => { sawSync = true; },
                    OnSend = () => { sawSync = true; }
                };

                var action = context.Bind(() => { return 13; }, syncContext, false);
                context.Reset();
                int result = action();

                Assert.IsTrue(sawSync, "Context did not use SyncContext for sync");
            }
        }
        public void SyncFunc_QueuedAfterStart_PreservesReturnValue()
        {
            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                object obj = thread.DoGet(() => { return new object(); });
                Assert.IsNotNull(obj, "ActionThread did not return result");
            }
        }
        public void SyncedWaitOrTimerCallback_Invoked_ReceivesParameter()
        {
            object parameter1 = new object();
            object arg1 = null;
            bool arg2 = false;

            using (ActionThread thread = new ActionThread())
            {
                thread.Start();

                // Have the ActionThread set "action"
                WaitOrTimerCallback action = thread.DoGet(() =>
                {
                    return Sync.SynchronizeWaitOrTimerCallback((a1, a2) => { arg1 = a1; arg2 = a2; });
                });

                action(parameter1, true);
                thread.Join();

                Assert.AreSame(parameter1, arg1, "Action did not receive parameter");
                Assert.IsTrue(arg2, "Action did not receive parameter");
            }
        }