/// <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); })); }
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"); }
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); }
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); }
/// <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)); }
/// <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)); }
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)); }