Example #1
0
 /// <summary>
 /// Updates the status if the predicate is satisfied. Returns true if the value was updated, i.e. if the predicate returned true.
 /// </summary>
 private bool UpdateStatusIf(Predicate <int> predicate, Func <int, int> statusUpdater)
 {
     // ReSharper disable once CSharpWarnings::CS0420    Ok to ignore "a reference to a volatile field will not be treated as volatile" for interlocked calls http://msdn.microsoft.com/en-us/library/4bw5ewxy(VS.80).aspx
     return(InterlockedSpin.ConditionallySwap(ref _mailboxStatus, status =>
     {
         var canUpdate = predicate(status);
         return Tuple.Create(canUpdate, canUpdate ? statusUpdater(status) : 0);
     }));
 }
Example #2
0
        public void When_a_shared_variable_is_updated_on_another_thread_Then_the_update_method_is_rerun_but_as_the_break_condition_is_fulfilled_it_do_not_update()
        {
            var sharedVariable                    = "";
            var hasEnteredUpdateMethod            = new ManualResetEvent(false);
            var okToContinue                      = new ManualResetEvent(false);
            var numberOfCallsToUpdateWhenSignaled = 0;

            //This is what we want to test:
            //  sharedVariable = ""
            //  Fork to two threads:
            //  THREAD 1                               THREAD 2
            //                                         Call InterlockedSpin.Swap
            //                                             It calls updateWhenSignaled(0)
            //                                                Signal thread 1 it can do it's work, and wait for it
            //  set sharedVariable = "-"
            //  signal thread 2 it can continue
            //  and wait for it.
            //                                                 Since value=="" we do not want to break
            //                                                 return <false,"updated","update"> from updateWhenSignaled
            //                                             Interlocked.CompareExchange will update sharedVariable to "updated" if it still is ""
            //                                               which it isn't so it will fail. It will then loop.
            //                                             Call updateWhenSignaled("-")
            //                                                 Since value!="" we want to break
            //                                                 return <true,"updated","break"> from updateWhenSignaled
            //                                             Since first item in tuple==true, we break and return item 3: "break"
            //  Test that sharedVariable="-"
            //  Test that updateWhenSignaled was called twice
            //  Test that return from updateWhenSignaled is "break"

            Func <string, Tuple <bool, string, string> > updateWhenSignaled = s =>
            {
                numberOfCallsToUpdateWhenSignaled++;
                hasEnteredUpdateMethod.Set();                  //Signal to start-thread that we have entered the update method (it will chang
                okToContinue.WaitOne(TimeSpan.FromSeconds(2)); //Wait to be signalled
                var shouldUpdate = s == "";
                return(Tuple.Create(shouldUpdate, "updated", shouldUpdate ? "update" : "break"));
            };
            string result = "";
            var    task   = Task.Run(() => { result = InterlockedSpin.ConditionallySwap(ref sharedVariable, updateWhenSignaled); });

            hasEnteredUpdateMethod.WaitOne(TimeSpan.FromSeconds(2));
            sharedVariable = "-";
            okToContinue.Set();
            task.Wait(TimeSpan.FromSeconds(2));

            sharedVariable.ShouldBe("-");
            numberOfCallsToUpdateWhenSignaled.ShouldBe(2);
            result.ShouldBe("break");
        }
Example #3
0
        public void When_a_shared_variable_is_updated_on_another_thread_Then_the_update_method_is_rerun_using_tuples()
        {
            var sharedVariable                    = "";
            var hasEnteredUpdateMethod            = new ManualResetEvent(false);
            var okToContinue                      = new ManualResetEvent(false);
            var numberOfCallsToUpdateWhenSignaled = 0;

            //This is what we want to test:
            //  sharedVariable = ""
            //  Fork to two threads:
            //  THREAD 1                               THREAD 2
            //                                         Call InterlockedSpin.Swap
            //                                             It calls updateWhenSignaled(0)
            //                                                Signal thread 1 it can do it's work, and wait for it
            //  set sharedVariable = "-"
            //  signal thread 2 it can continue
            //  and wait for it.
            //                                                 return "updated" from updateWhenSignaled
            //                                             Interlocked.CompareExchange will update sharedVariable to "updated" if it still is ""
            //                                               which it isn't so it will fail. It will then loop.
            //                                             Call updateWhenSignaled("-")
            //                                                 return "updated" from updateWhenSignaled
            //                                             Interlocked.CompareExchange will update sharedVariable to "updated" if it still is "-"
            //                                               which it is, and we return.
            //  Test that sharedVariable="updated"
            //  Test that updateWhenSignaled was called twice

            Func <string, Tuple <bool, string, string> > updateWhenSignaled = i =>
            {
                numberOfCallsToUpdateWhenSignaled++;
                hasEnteredUpdateMethod.Set();                  //Signal THREAD 1 to update sharedVariable
                okToContinue.WaitOne(TimeSpan.FromSeconds(2)); //Wait for THREAD 1
                return(Tuple.Create(true, "updated", "returnValue"));
            };
            string result;
            var    task = Task.Run(() => { result = InterlockedSpin.ConditionallySwap(ref sharedVariable, updateWhenSignaled); });

            hasEnteredUpdateMethod.WaitOne(TimeSpan.FromSeconds(2)); //Wait for THREAD 2 to enter updateWhenSignaled
            sharedVariable = "-";
            okToContinue.Set();                                      //Signal THREAD 1 it can continue in updateWhenSignaled
            task.Wait(TimeSpan.FromSeconds(2));                      //Wait for THREAD 1

            sharedVariable.ShouldBe("updated");
            numberOfCallsToUpdateWhenSignaled.ShouldBe(2);
        }
Example #4
0
        public void When_a_shared_variable_is_updated_on_another_thread_Then_the_update_method_is_rerun()
        {
            var sharedVariable                    = 0;
            var hasEnteredUpdateMethod            = new ManualResetEvent(false);
            var okToContinue                      = new ManualResetEvent(false);
            var numberOfCallsToUpdateWhenSignaled = 0;

            //This is what we want to test:
            //  sharedVariable = 0
            //  Fork to two threads:
            //  THREAD 1                               THREAD 2
            //                                         Call InterlockedSpin.Swap
            //                                             It calls updateWhenSignaled(0)
            //                                                Signal thread 1 it can do it's work, and wait for it
            //  set sharedVariable = 42
            //  signal thread 2 it can continue
            //  and wait for it.
            //                                                 return 4711 from updateWhenSignaled
            //                                             Interlocked.CompareExchange will update sharedVariable to 4711 if it still is 0
            //                                               which it isn't so it will fail. It will then loop.
            //                                             Call updateWhenSignaled(42)
            //                                                 return 4711 from updateWhenSignaled
            //                                             Interlocked.CompareExchange will update sharedVariable to 4711 if it still is 42
            //                                               which it is, and we return.
            //  Test that sharedVariable=42
            //  Test that updateWhenSignaled was called twice

            Func <int, int> updateWhenSignaled = i =>
            {
                numberOfCallsToUpdateWhenSignaled++;
                hasEnteredUpdateMethod.Set();                   //Signal THREAD 1 to update sharedVariable
                okToContinue.WaitOne(TimeSpan.FromSeconds(2));  //Wait for THREAD 1
                return(4711);
            };
            var task = Task.Run(() => InterlockedSpin.Swap(ref sharedVariable, updateWhenSignaled));

            hasEnteredUpdateMethod.WaitOne(TimeSpan.FromSeconds(2)); //Wait for THREAD 2 to enter updateWhenSignaled
            sharedVariable = 42;
            okToContinue.Set();                                      //Signal THREAD 1 it can continue in updateWhenSignaled
            task.Wait(TimeSpan.FromSeconds(2));                      //Wait for THREAD 1

            sharedVariable.Should().Be(4711);
            numberOfCallsToUpdateWhenSignaled.Should().Be(2);
        }
Example #5
0
 /// <summary>
 /// Swaps out the children container, by calling <paramref name="updater" />  to produce the new container.
 /// If the underlying container has been updated while <paramref name="updater" /> was called,
 /// <paramref name="updater" /> will be called again with the new container. This will repeat until the
 /// container can be swapped out.
 /// </summary>
 /// <param name="updater">A function that returns a new container.</param>
 /// <returns>The new updated <see cref="ChildrenContainer"/></returns>
 private IChildrenContainer UpdateChildrenRefs(Func <IChildrenContainer, IChildrenContainer> updater)
 {
     return(InterlockedSpin.Swap(ref _childrenContainerDoNotCallMeDirectly, updater));
 }
Example #6
0
 /// <summary>
 /// Swaps out the children container, by calling <paramref name="updater"/>  to produce the new container.
 /// If the underlying container has been updated while <paramref name="updater"/> was called,
 /// <paramref name="updater"/> will be called again with the new container. This will repeat until the
 /// container can be swapped out, or until <see cref="Tuple{T1,T2,T3}.Item1"/> contains <c>false</c>.
 /// <para>The returned tuple should contain:</para>
 /// <para>Item1: <c>true</c> if the container should be updated; <c>false</c> to not update and return Item3</para>
 /// <para>Item2: The new container (will only be used if Item1=<c>true</c>)</para>
 /// <para>Item3: The return value</para>
 /// </summary>
 /// <param name="updater">A function that returns a new container.</param>
 /// <returns>The third value of the tuple that <paramref name="updater"/> returned.</returns>
 private TReturn UpdateChildrenRefs <TReturn>(Func <ChildrenContainer, Tuple <bool, ChildrenContainer, TReturn> > updater)
 {
     return(InterlockedSpin.ConditionallySwap <ChildrenContainer, TReturn>(ref _childrenContainerDoNotCallMeDirectly, updater));
 }
Example #7
0
 private int UpdateStatus(Func <int, int> statusUpdater)
 {
     // ReSharper disable once CSharpWarnings::CS0420    Ok to ignore "a reference to a volatile field will not be treated as volatile" for interlocked calls http://msdn.microsoft.com/en-us/library/4bw5ewxy(VS.80).aspx
     return(InterlockedSpin.Swap(ref _mailboxStatus, statusUpdater));
 }