Beispiel #1
0
        public void NoOdds()
        {
            var x = new Shielded<int>();

            int preCommitFails = 0;
            // we will not allow any odd number to be committed into x.
            Shield.PreCommit(() => (x.Value & 1) == 1, () => {
                Interlocked.Increment(ref preCommitFails);
                throw new InvalidOperationException();
            });

            int transactionCount = 0;
            Task.WaitAll(
                Enumerable.Range(1, 100).Select(i => Task.Factory.StartNew(() =>
                {
                    try
                    {
                        Shield.InTransaction(() =>
                        {
                            Interlocked.Increment(ref transactionCount);
                            int a = x;
                            Thread.Sleep(5);
                            x.Value = a + i;
                        });
                    }
                    catch (InvalidOperationException) { }
                }, TaskCreationOptions.LongRunning)).ToArray());
            Assert.AreEqual(50, preCommitFails);
            Assert.AreEqual(2550, x);
            // just to confirm validity of test! not really a fail if this fails.
            Assert.Greater(transactionCount, 100);
        }
Beispiel #2
0
        public void ConditionalTest()
        {
            var x = new Shielded<int>();
            var testCounter = 0;
            var triggerCommits = 0;

            Shield.Conditional(() => {
                Interlocked.Increment(ref testCounter);
                return x > 0 && (x & 1) == 0;
            },
            () => {
                Shield.SideEffect(() =>
                    Interlocked.Increment(ref triggerCommits));
                Assert.IsTrue(x > 0 && (x & 1) == 0);
            });

            const int count = 1000;
            ParallelEnumerable.Repeat(1, count).ForAll(i =>
                Shield.InTransaction(() => x.Modify((ref int n) => n++)));

            // one more, for the first call to Conditional()! btw, if this conditional were to
            // write anywhere, he might conflict, and an interlocked counter would give more due to
            // repetitions. so, this confirms reader progress too.
            Assert.AreEqual(count + 1, testCounter);
            // every change triggers it, but by the time it starts, another transaction might have
            // committed, so this is not a fixed number.
            Assert.Greater(triggerCommits, 0);

            // a conditional which does not depend on any Shielded is not allowed!
            int a = 5;
            Assert.Throws<InvalidOperationException>(() =>
                Shield.Conditional(() => a > 10, () => { }));

            bool firstTime = true;
            var x2 = new Shielded<int>();
            // this one succeeds in registering, but fails as soon as it gets triggered, due to changing it's
            // test's access pattern to an empty set.
            Shield.Conditional(() => {
                if (firstTime)
                {
                    firstTime = false;
                    return x2 == 0;
                }
                else
                    // this is of course invalid, and when reaching here we have not touched any Shielded obj.
                    return true;
            }, () => { });

            try
            {
                // this will trigger the conditional
                Shield.InTransaction(() => x2.Modify((ref int n) => n++));
                Assert.Fail();
            }
            catch (AggregateException aggr)
            {
                Assert.AreEqual(1, aggr.InnerExceptions.Count);
                Assert.AreEqual(typeof(InvalidOperationException), aggr.InnerException.GetType());
            }
        }
Beispiel #3
0
        public void Run()
        {
            Console.WriteLine("Queue test...");

            ProcessorSlot.Set(Environment.ProcessorCount - 1);
            CountTracking();
            Subscribe();

            var maxQueueCount = new Shielded<int>();
            Shield.Conditional(() => _queue.Count > maxQueueCount, () => {
                maxQueueCount.Assign(_queue.Count);
                return true;
            });

            // create ItemCount items and push them in the queue.
            Stopwatch stopwatch = new Stopwatch();
            var items = Enumerable.Range(1, ItemCount).Select(
                i => new Item() { Id = Guid.NewGuid(), Code = i, Amount = 100m * i }).ToArray();
            stopwatch.Start();
            for (int i = 0; i < ItemCount / 100; i++)
            {
                Shield.InTransaction(() => {
                    for (int j = 0; j < 100; j++)
                        _queue.Append(items[i*100 + j]);
                });
            }

            Console.WriteLine("..all items added, waiting.");
            _barrier.SignalAndWait();
            var time = stopwatch.ElapsedMilliseconds;
            Console.WriteLine(" -- completed in {0} ms, with {1} max queue count.", time, maxQueueCount.Read);
        }
Beispiel #4
0
        private void CountTracking()
        {
            int reportEvery = 10000;
            Shielded<int> lastReport = new Shielded<int>(0);
            Shielded<DateTime> lastTime = new Shielded<DateTime>(DateTime.UtcNow);

            Shield.Conditional(() => _processed >= lastReport + reportEvery, () =>
            {
                DateTime newNow = DateTime.UtcNow;
                int count = _processed;
                int speed = (count - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds;
                lastTime.Assign(newNow);
                lastReport.Modify((ref int n) => n += reportEvery);
                int sc = _subscribeCount;
                int ptc = _processTestCount;
                int pbc = _processBodyCount;
                Shield.SideEffect(() =>
                {
                    Console.WriteLine(
                        "{0} at {1} item/s, stats ( {2}, {3}, {4} )",
                        count, speed, sc, ptc, pbc);
                });
                return true;
            });
        }
Beispiel #5
0
        public void EventTest()
        {
            var a = new Shielded<int>(1);
            var eventCount = new Shielded<int>();
            EventHandler<EventArgs> ev =
                (sender, arg) => eventCount.Commute((ref int e) => e++);

            Assert.Throws<InvalidOperationException>(() =>
                a.Changed.Subscribe(ev));

            Shield.InTransaction(() =>
            {
                a.Changed.Subscribe(ev);

                var t = new Thread(() =>
                    Shield.InTransaction(() =>
                        a.Modify((ref int x) => x++)));
                t.Start();
                t.Join();

                var t2 = new Thread(() =>
                    Shield.InTransaction(() =>
                        a.Modify((ref int x) => x++)));
                t2.Start();
                t2.Join();
            });
            Assert.AreEqual(0, eventCount);

            Shield.InTransaction(() => {
                a.Modify((ref int x) => x++);
            });
            Assert.AreEqual(1, eventCount);

            Thread tUnsub = null;
            Shield.InTransaction(() => {
                a.Changed.Unsubscribe(ev);
                a.Modify((ref int x) => x++);

                if (tUnsub == null)
                {
                    tUnsub = new Thread(() =>
                    {
                        Shield.InTransaction(() => {
                            a.Modify((ref int x) => x++);
                            a.Modify((ref int x) => x++);
                        });
                    });
                    tUnsub.Start();
                    tUnsub.Join();
                }
            });
            // the other thread must still see the subscription...
            Assert.AreEqual(3, eventCount);

            Shield.InTransaction(() => a.Modify((ref int x) => x++));
            Assert.AreEqual(3, eventCount);
        }
Beispiel #6
0
 public void ExceptionWhenTryingToCommit()
 {
     var a = new Shielded<int>();
     using (Shield.WhenCommitting(a, _ => { throw new CustomException(); }))
     using (var cont = Shield.RunToCommit(5000, () => a.Value = 5))
     {
         var aggr = Assert.Throws<AggregateException>(() => cont.TryCommit());
         Assert.IsInstanceOf<CustomException>(aggr.InnerExceptions.Single());
     }
 }
Beispiel #7
0
        public void FieldsTest()
        {
            var a = new Shielded<int>();
            using (var continuation = Shield.RunToCommit(1000, () => { int _ = a.Value; }))
            {
                var fields = continuation.Fields;
                Assert.AreEqual(1, fields.Length);
                Assert.AreSame(a, fields[0].Field);
                Assert.IsFalse(fields[0].HasChanges);

                continuation.InContext(f =>
                    Assert.AreSame(fields, f));
            }
        }
Beispiel #8
0
        public void CommuteInACommute()
        {
            var a = new Shielded<int>();
            var b = new Shielded<int>();

            Assert.Throws<InvalidOperationException>(() =>
                // there is only one _blockEnlist, and if it is "reused" by an inner call, it
                // would get set to null when the inner commute ends. this would allow later code
                // in the outer commute to violate the access restriction.
                Shield.InTransaction(() =>
                    a.Commute((ref int aRef) => {
                        a.Commute((ref int aRef2) => aRef2++);
                        b.Value = 1;
                    })));
        }
Beispiel #9
0
 public void BasicTest()
 {
     var a = new Shielded<int>(10);
     Shield.InTransaction(() => {
         a.Value = 20;
         Assert.AreEqual(20, a);
         Shield.ReadOldState(() => {
             Assert.AreEqual(10, a);
             a.Value = 30;
             Assert.AreEqual(10, a);
             a.Modify((ref int x) =>
                 Assert.AreEqual(30, x));
         });
         Assert.AreEqual(30, a.Value);
     });
     Assert.AreEqual(30, a.Value);
 }
Beispiel #10
0
        public void CommuteInvariantProblem()
        {
            // since pre-commits have no limitations on access, they cannot safely
            // execute within the commute sub-transaction. if they would, then this
            // test would fail on the last assertion. instead, pre-commits cause commutes
            // to degenerate.

            var testField = new Shielded<int>();
            var effectField = new Shielded<int>();
            var failCommitCount = new Shielded<int>();
            var failVisibleCount = 0;

            // check if the effect field was written to, that the testField is even.
            Shield.PreCommit(() => effectField > 0, () => {
                if ((testField & 1) == 1)
                {
                    Interlocked.Increment(ref failVisibleCount);
                    // this will always fail to commit, confirming that the transaction
                    // is already bound to fail. but, the failVisibleCount will be >0.
                    failCommitCount.Modify((ref int n) => n++);
                }
            });

            var thread = new Thread(() => {
                // if the testField is even, increment the effectField commutatively.
                foreach (int i in Enumerable.Range(1, 1000))
                    Shield.InTransaction(() => {
                        if ((testField & 1) == 0)
                        {
                            effectField.Commute((ref int n) => n++);
                        }
                    });
            });
            thread.Start();

            foreach (int i in Enumerable.Range(1, 1000))
                Shield.InTransaction(() => {
                    testField.Modify((ref int n) => n++);
                });
            thread.Join();

            Assert.AreEqual(0, failCommitCount);
            Assert.AreEqual(0, failVisibleCount);
        }
Beispiel #11
0
        public void CommuteTest()
        {
            var a = new Shielded<int>();

            Shield.InTransaction(() => a.Commute((ref int n) => n++));
            Assert.AreEqual(1, a);

            Shield.InTransaction(() =>
            {
                Assert.AreEqual(1, a);
                a.Commute((ref int n) => n++);
                Assert.AreEqual(2, a);
            });
            Assert.AreEqual(2, a);

            Shield.InTransaction(() =>
            {
                a.Commute((ref int n) => n++);
                Assert.AreEqual(3, a);
            });
            Assert.AreEqual(3, a);

            int transactionCount = 0, commuteCount = 0;
            ParallelEnumerable.Repeat(1, 100).ForAll(i => Shield.InTransaction(() => {
                Interlocked.Increment(ref transactionCount);
                a.Commute((ref int n) => {
                    Interlocked.Increment(ref commuteCount);
                    Thread.Sleep(10); // needs this.. (running on Mono 2.10)
                    n++;
                });
            }));
            Assert.AreEqual(103, a);
            // commutes never conflict (!)
            Assert.AreEqual(100, transactionCount);
            Assert.Greater(commuteCount, 100);

            Shield.InTransaction(() => {
                a.Commute((ref int n) => n -= 3);
                a.Commute((ref int n) => n--);
            });
            Assert.AreEqual(99, a);
        }
Beispiel #12
0
        public void BasicRunToCommit()
        {
            var a = new Shielded<int>(5);
            using (var cont = Shield.RunToCommit(5000,
                () => {
                    if (a == 5)
                        a.Value = 20;
                }))
            {
                int runCount = 0, insideIfCount = 0;
                var t = new Thread(() => Shield.InTransaction(() => {
                    Interlocked.Increment(ref runCount);
                    if (a == 5) // this will block, and continue after the Commit call below
                    {
                        Interlocked.Increment(ref insideIfCount);
                        a.Value = 10;
                    }
                }));
                t.Start();
                Thread.Sleep(100);
                Assert.AreEqual(1, runCount);
                Assert.AreEqual(0, insideIfCount);

                cont.InContext(() => Assert.AreEqual(20, a));
                Assert.AreEqual(5, a);
                var t2 = new Thread(cont.Commit);
                t2.Start();
                t2.Join();
                t.Join();
                Assert.AreEqual(1, runCount);
                Assert.AreEqual(0, insideIfCount);
                Assert.AreEqual(20, a);

                Assert.IsFalse(cont.TryCommit());
                Assert.IsFalse(cont.TryRollback());
                Assert.IsTrue(cont.Committed);
            }
            Assert.AreEqual(20, a);
        }
Beispiel #13
0
        public void ShieldedLocalVisibility()
        {
            var x = new Shielded<int>();
            var local = new ShieldedLocal<int>();

            var didItRun = false;
            using (Shield.WhenCommitting(_ => {
                didItRun = true;
                Assert.AreEqual(10, local);
            }))
            {
                Shield.InTransaction(() => {
                    x.Value = 1;
                    local.Value = 10;
                });
            }
            Assert.IsTrue(didItRun);

            using (var continuation = Shield.RunToCommit(Timeout.Infinite, () => {
                local.Value = 20;
            }))
            {
                continuation.InContext(() =>
                    Assert.AreEqual(20, local));
            }

            didItRun = false;
            Shield.InTransaction(() => {
                local.Value = 30;
                Shield.SyncSideEffect(() => {
                    didItRun = true;
                    Assert.AreEqual(30, local);
                });
            });
            Assert.IsTrue(didItRun);
        }
Beispiel #14
0
        public static void DictionaryPoolTest()
        {
            int numThreads = Environment.ProcessorCount;
            int numItems = 1000000;
            var tree = new ShieldedDictNc<int, int>();
            var barrier = new Barrier(numThreads + 1);
            var counter = 0;
            int reportEvery = 10000;
            var lastReport = 0;
            long time;

            int x;
            var y = new Shielded<int>();

            _timer = new Stopwatch();
            _timer.Start();
            time = _timer.ElapsedMilliseconds;
            foreach (var k in Enumerable.Repeat(1, numItems))
                Shield.InTransaction(() => { });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Empty transactions in {0} ms.", time);

            var bags = new List<Action>[numThreads];
            var threads = new Thread[numThreads];
            for (int i = 0; i < numThreads; i++)
            {
                var bag = bags[i] = new List<Action>();
                threads[i] = new Thread(() => {
                    foreach (var a in bag)
                    {
                        try
                        {
                            a();
                        }
                        catch
                        {
                            Console.Write(" * ");
                        }
                    }
                    barrier.SignalAndWait();
                });
            }

            var lastTime = _timer.ElapsedMilliseconds;
            foreach (var i in Enumerable.Range(0, numItems))
            {
                var index = i;
                bags[i % numThreads].Add(() => Shield.InTransaction(() => {
                    tree.Add(index, index);
                    Shield.SideEffect(() => {
                        var last = lastReport;
                        var count = Interlocked.Increment(ref counter);
                        var newNow = _timer.ElapsedMilliseconds;
                        if (count > last + reportEvery &&
                            Interlocked.CompareExchange(ref lastReport, last + reportEvery, last) == last)
                        {
                            var speed = reportEvery * 1000 / (newNow - lastTime);
                            lastTime = newNow; // risky, but safe ;)
                            Console.Write("\n{0} at {1} item/s", last + reportEvery, speed);
                        }
                    });
                }));
            }
            lastTime = _timer.ElapsedMilliseconds;
            for (int i = 0; i < numThreads; i++)
                threads[i].Start();

            barrier.SignalAndWait();
            time = _timer.ElapsedMilliseconds;
            Console.WriteLine("\nTOTAL: {0} ms, at {1} ops/s", time, numItems * 1000 / time);

            Console.WriteLine("\nReading sequentially...");
            time = _timer.ElapsedMilliseconds;
            var keys = Shield.InTransaction(() => tree.Keys);
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Keys read in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            Shield.InTransaction(() => {
                foreach (var kvp in tree)
                    x = kvp.Value;
            });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by enumerator in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            Shield.InTransaction(() => {
                foreach (var kvp in tree.OrderBy(kvp => kvp.Key))
                    x = kvp.Value;
            });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by sorted enumerator in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            Shield.InTransaction(() => {
                foreach (var k in keys)
                    x = tree[k];
            });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by key in one trans in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            foreach (var k in keys)
                x = tree[k];
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by key separately in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            keys.AsParallel().ForAll(k => x = tree[k]);
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by key in parallel in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            foreach (var k in Enumerable.Repeat(1, numItems))
            {
                var a = y.Value;
            }
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("One field out-of-tr. reads in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            foreach (var k in Enumerable.Repeat(1, numItems))
                Shield.InTransaction(() => { });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Empty transactions in {0} ms.", time);
        }
Beispiel #15
0
        /// <summary>
        /// Creates a BetShop, and tries to buy a large number of random tickets. Afterwards it
        /// checks that the rule limiting same ticket winnings is not violated.
        /// </summary>
        public static void BetShopTest()
        {
            int numEvents = 100;
            var betShop = new BetShop(numEvents);
            var randomizr = new Random();
            int reportEvery = 1000;
            var lastReport = new Shielded<int>(0);
            var lastTime = new Shielded<DateTime>(DateTime.UtcNow);
            long time;

            using (var reportingCond = Shield.Conditional(
                () => betShop.Tickets.Count >= lastReport + reportEvery,
                () => {
                    DateTime newNow = DateTime.UtcNow;
                    int count = betShop.Tickets.Count;
                    int speed = (count - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds;
                    lastTime.Value = newNow;
                    lastReport.Modify((ref int n) => n += reportEvery);
                    Shield.SideEffect(() =>
                    {
                        Console.Write("\n{0} at {1} item/s", count, speed);
                    });
                }))
            {
                time = mtTest("bet shop w/ " + numEvents, 50000, i =>
                {
                    decimal payIn = (randomizr.Next(10) + 1m) * 1;
                    int event1Id = randomizr.Next(numEvents) + 1;
                    int event2Id = randomizr.Next(numEvents) + 1;
                    int event3Id = randomizr.Next(numEvents) + 1;
                    int offer1Ind = randomizr.Next(3);
                    int offer2Ind = randomizr.Next(3);
                    int offer3Ind = randomizr.Next(3);
                    return Task.Factory.StartNew(() => Shield.InTransaction(() =>
                    {
                        var offer1 = betShop.Events[event1Id].BetOffers[offer1Ind];
                        var offer2 = betShop.Events[event2Id].BetOffers[offer2Ind];
                        var offer3 = betShop.Events[event3Id].BetOffers[offer3Ind];
                        betShop.BuyTicket(payIn, offer1, offer2, offer3);
                    }));
                });
            }
            //}

            var totalCorrect = betShop.VerifyTickets();
            Console.WriteLine(" {0} ms with {1} tickets paid in and is {2}.",
                time, betShop.Tickets.Count, totalCorrect ? "correct" : "incorrect");
        }
Beispiel #16
0
        static void SimpleOps()
        {
            long time;
            _timer = Stopwatch.StartNew();
            var numItems = 1000000;
            var repeatsPerTrans = 50;

            Console.WriteLine(
                "Testing simple ops with {0} iterations, and repeats per trans (N) = {1}",
                numItems, repeatsPerTrans);

            var accessTest = new Shielded<int>();

            Timed("WARM UP", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        accessTest.Value = 3;
                        var a = accessTest.Value;
                        accessTest.Modify((ref int n) => n = 5);
                        a = accessTest.Value;
                    });
            });

            var emptyTime = Timed("empty transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => { });
            });

            var emptyReturningTime = Timed("1 empty transaction w/ result", numItems, () => {
                // this version uses the generic, result-returning InTransaction, which involves creation
                // of a closure, i.e. an allocation.
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => 5);
            });

            var outOfTrReadTime = Timed("N out-of-tr. reads", numItems, () => {
                // this version uses the generic, result-returning InTransaction, which involves creation
                // of a closure, i.e. an allocation.
                foreach (var k in Enumerable.Repeat(1, numItems * repeatsPerTrans))
                {
                    var a = accessTest.Value;
                }
            });

            // the purpose here is to get a better picture of the expense of using Shielded. a more
            // complex project would probably, during one transaction, repeatedly access the same
            // field. does this cost much more than a single-access transaction? if it is the same
            // field, then any significant extra expense is unacceptable.

            var oneReadTime = Timed("1-read transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        var a = accessTest.Value;
                    });
            });

            var nReadTime = Timed("N-reads transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        int a;
                        for (int i = 0; i < repeatsPerTrans; i++)
                            a = accessTest.Value;
                    });
            });

            var oneReadModifyTime = Timed("1-read-1-modify tr.", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        var a = accessTest.Value;
                        accessTest.Modify((ref int n) => n = 1);
                    });
            });

            // Assign is no longer commutable, for performance reasons. It is faster,
            // particularly when repeated (almost 10 times), and you can see the difference
            // that not reading the old value does.
            var oneReadAssignTime = Timed("1-read-1-assign tr.", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        var a = accessTest.Value;
                        accessTest.Value = 1;
                    });
            });

            var oneModifyTime = Timed("1-modify transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => accessTest.Modify((ref int n) => n = 1));
            });

            var nModifyTime = Timed("N-modify transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        for (int i = 0; i < repeatsPerTrans; i++)
                            accessTest.Modify((ref int n) => n = 1);
                    });
            });

            var accessTest2 = new Shielded<int>();
            var modifyModifyTime = Timed("modify-modify transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        accessTest.Modify((ref int n) => n = 1);
                        accessTest2.Modify((ref int n) => n = 2);
                    });
            });

            // here Modify is the first call, making all Reads as fast as can be,
            // reading direct from local storage.
            var oneModifyNReadTime = Timed("1-modify-N-reads tr.", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        accessTest.Modify((ref int n) => n = 1);
                        int a;
                        for (int i = 0; i < repeatsPerTrans; i++)
                            a = accessTest.Value;
                    });
            });

            var oneAssignTime = Timed("1-assign transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => accessTest.Value = 1);
            });

            var nAssignTime = Timed("N-assigns transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => {
                        for (int i = 0; i < repeatsPerTrans; i++)
                            accessTest.Value = 1;
                    });
            });

            var oneCommuteTime = Timed("1-commute transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems))
                    Shield.InTransaction(() => accessTest.Commute((ref int n) => n = 1));
            });

            var nCommuteTime = Timed("N-commute transactions", numItems, () => {
                foreach (var k in Enumerable.Repeat(1, numItems/10))
                    Shield.InTransaction(() => {
                        for (int i = 0; i < repeatsPerTrans; i++)
                            accessTest.Commute((ref int n) => n = 1);
                    });
            });

            Console.WriteLine("\ncost of empty transaction = {0:0.000} us", emptyTime / (numItems / 1000.0));
            Console.WriteLine("cost of the closure in InTransaction<T> = {0:0.000} us",
                              (emptyReturningTime - emptyTime) / (numItems / 1000.0));
            Console.WriteLine("cost of an out-of-tr. read = {0:0.000} us",
                              outOfTrReadTime * 1000.0 / (numItems * repeatsPerTrans));
            Console.WriteLine("cost of the first read = {0:0.000} us",
                              (oneReadTime - emptyTime) / (numItems / 1000.0));
            Console.WriteLine("cost of an additional read = {0:0.000} us",
                              (nReadTime - oneReadTime) / ((repeatsPerTrans - 1) * numItems / 1000.0));
            Console.WriteLine("cost of Modify after read = {0:0.000} us",
                              (oneReadModifyTime - oneReadTime) / (numItems / 1000.0));
            Console.WriteLine("cost of Assign after read = {0:0.000} us",
                              (oneReadAssignTime - oneReadTime) / (numItems / 1000.0));
            Console.WriteLine("cost of the first Modify = {0:0.000} us",
                              (oneModifyTime - emptyTime) / (numItems / 1000.0));
            Console.WriteLine("cost of an additional Modify = {0:0.000} us",
                              (nModifyTime - oneModifyTime) / ((repeatsPerTrans - 1) * numItems / 1000.0));
            Console.WriteLine("cost of a second, different Modify = {0:0.000} us",
                              (modifyModifyTime - oneModifyTime) / (numItems / 1000.0));
            Console.WriteLine("cost of a read after Modify = {0:0.000} us",
                              (oneModifyNReadTime - oneModifyTime) / (repeatsPerTrans * numItems / 1000.0));
            Console.WriteLine("cost of the first Assign = {0:0.000} us",
                              (oneAssignTime - emptyTime) / (numItems / 1000.0));
            Console.WriteLine("cost of an additional Assign = {0:0.000} us",
                              (nAssignTime - oneAssignTime) / ((repeatsPerTrans - 1) * numItems / 1000.0));
            Console.WriteLine("cost of the first commute = {0:0.000} us",
                              (oneCommuteTime - emptyTime) / (numItems / 1000.0));
            Console.WriteLine("cost of an additional commute = {0:0.000} us",
                              (nCommuteTime*10 - oneCommuteTime) / ((repeatsPerTrans - 1) * numItems / 1000.0));
        }
Beispiel #17
0
        public static void TreeTest()
        {
            int numTasks = 100000;

            var tree = new ShieldedTreeNc<Guid, TreeItem>();
            int transactionCount = 0;
            Shielded<int> lastReport = new Shielded<int>(0);
            Shielded<int> countComplete = new Shielded<int>(0);

            if (true)
            {
                var treeTime = mtTest("tree", numTasks, i =>
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var item1 = new TreeItem();
                        Shield.InTransaction(() =>
                        {
                            //Interlocked.Increment(ref transactionCount);
                            tree.Add(item1.Id, item1);
            //                            countComplete.Commute((ref int c) => c++);
                        }
                        );
                    }
                    );
                }
                );
                Guid? previous = null;
                bool correct = true;
                Shield.InTransaction(() =>
                {
                    int count = 0;
                    foreach (var item in tree)
                    {
                        count++;
                        if (previous != null && previous.Value.CompareTo(item.Key) > 0)
                        {
                            correct = false;
                            break;
                        }
                        previous = item.Key;
                    }
                    correct = correct && (count == numTasks);
                }
                );
                Console.WriteLine("\n -- {0} ms with {1} iterations and is {2}.",
                    treeTime, transactionCount, correct ? "correct" : "incorrect");
            }

            if (true)
            {
                var dict = new ShieldedDictNc<Guid, TreeItem>();
                transactionCount = 0;
                Shield.InTransaction(() =>
                {
                    countComplete.Value = 0;
                    lastReport.Value = 0;
                }
                );

                var time = mtTest("dictionary", numTasks, i =>
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var item1 = new TreeItem();
                        Shield.InTransaction(() =>
                        {
                            //Interlocked.Increment(ref transactionCount);
                            dict[item1.Id] = item1;
            //                            countComplete.Commute((ref int c) => c++);
                        }
                        );
                    }
                    );
                }
                );
                Console.WriteLine("\n -- {0} ms with {1} iterations. Not sorted.",
                time, transactionCount);
            }

            if (true)
            {
                ConcurrentDictionary<Guid, TreeItem> dict = new ConcurrentDictionary<Guid, TreeItem>();

                var time = mtTest("ConcurrentDictionary", numTasks, i =>
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var item1 = new TreeItem();
                        dict[item1.Id] = item1;
                    }
                    );
                }
                );
                Console.WriteLine("\n -- {0} ms with {1} iterations. Not sorted.",
                time, numTasks);
            }
        }
Beispiel #18
0
        public void DictionaryAccessExpandingTest()
        {
            var d = new ShieldedDict <int, object>();

            // various combinations - one key is either written or just read, and the
            // WhenCommitting sub tries to mess with another key, or to promote the
            // read key.

            Shield.InTransaction(() => {
                d[1] = new object();
                d[2] = new object();
            });

            // WhenCommitting does not fire unless at least something changed, so we need this
            Shielded <int> x = new Shielded <int>();

            // reader promotion to writer not allowed
            using (Shield.WhenCommitting(fs => d[2] = new object()))
            {
                Assert.Throws <AggregateException>(() =>
                                                   Shield.InTransaction(() => {
                    x.Value = 1;
                    var obj = d[2];
                }));
            }
            // new read not allowed
            using (Shield.WhenCommitting(fs => { var obj = d[2]; }))
            {
                Assert.Throws <AggregateException>(() =>
                                                   Shield.InTransaction(() => {
                    x.Value = 1;
                    var obj = d[1];
                }));
            }
            // new write not allowed
            using (Shield.WhenCommitting(fs => d[2] = new object()))
            {
                Assert.Throws <AggregateException>(() =>
                                                   Shield.InTransaction(() => {
                    x.Value = 1;
                    var obj = d[1];
                }));
            }
            // same checks, but in situations when we did a write in the dict
            using (Shield.WhenCommitting(fs => d[2] = new object()))
            {
                Assert.Throws <AggregateException>(() =>
                                                   Shield.InTransaction(() => {
                    d[1]    = new object();
                    var obj = d[2];
                }));
            }
            using (Shield.WhenCommitting(fs => { var obj = d[2]; }))
            {
                Assert.Throws <AggregateException>(() =>
                                                   Shield.InTransaction(() => {
                    d[1] = new object();
                }));
            }
            using (Shield.WhenCommitting(fs => d[2] = new object()))
            {
                Assert.Throws <AggregateException>(() =>
                                                   Shield.InTransaction(() => {
                    d[1] = new object();
                }));
            }

            // removing should likewise be restricted
            using (Shield.WhenCommitting(fs =>
            {
                d.Remove(1);
                Assert.Throws <InvalidOperationException>(
                    () => d.Remove(2));
            }))
            {
                Shield.InTransaction(() => {
                    d[1] = new object();
                });
            }
            // the exception was caught, and the WhenCommiting delegate committed
            Assert.IsFalse(d.ContainsKey(1));
            Shield.InTransaction(() => d[1] = new object());

            // finally, something allowed - reading from read or written, and writing into written
            using (Shield.WhenCommitting(fs =>
            {
                var obj = d[1];
                var obj2 = d[2];
                d[2] = new object();
            }))
            {
                Shield.InTransaction(() => {
                    var obj = d[1];
                    d[2]    = new object();
                });
            }
        }
Beispiel #19
0
        public void ComplexCommute()
        {
            // some more complex commute combinations. first, with ShieldedSeq ops.
            var seq = new ShieldedSeq<int>();

            Shield.InTransaction(() => {
                // test for potential disorder of the seq commutes.
                seq.Append(1);
                seq.Clear();
                Assert.IsFalse(seq.HasAny);
                Assert.AreEqual(0, seq.Count);
            });

            Shield.InTransaction(() => {
                seq.Append(1);
                seq.Append(2);
                seq.Append(3);
                seq.Remove(2);
                Assert.IsTrue(seq.HasAny);
                Assert.AreEqual(2, seq.Count);
                Assert.AreEqual(1, seq[0]);
                Assert.AreEqual(3, seq[1]);
                seq.Clear();
                Assert.IsFalse(seq.HasAny);
                Assert.AreEqual(0, seq.Count);
            });

            Shield.InTransaction(() => { seq.Append(1); seq.Append(2); });
            Assert.AreEqual(1, seq[0]);
            Assert.AreEqual(2, seq[1]);
            int transactionCount = 0;
            Thread oneTimer = null;
            Shield.InTransaction(() => {
                // here's a weird one - the seq is only partially commuted, due to reading
                // from the head, but it still commutes with a trans that is only appending.
                transactionCount++;
                Assert.AreEqual(1, seq.TakeHead());
                // Count or tail were not read! Clearing can commute with appending.
                seq.Clear();
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(3);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(1, transactionCount);
            Assert.AreEqual(0, seq.Count);
            Assert.IsFalse(seq.HasAny);

            Shield.InTransaction(() => { seq.Append(1); seq.Append(2); });
            Assert.AreEqual(1, seq[0]);
            Assert.AreEqual(2, seq[1]);
            transactionCount = 0;
            oneTimer = null;
            Shield.InTransaction(() => {
                // same as above, but with appending, does not work. reading the _head screws it up,
                // because you could continue from the head to the last item.
                transactionCount++;
                Assert.AreEqual(1, seq.TakeHead());
                seq.Append(4);
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(3);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(2, transactionCount);
            Assert.AreEqual(3, seq.Count);
            Assert.IsTrue(seq.HasAny);
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(3, seq[1]);
            Assert.AreEqual(4, seq[2]);

            Shield.InTransaction(() => { seq.Clear(); seq.Append(1); seq.Append(2); });
            Assert.AreEqual(1, seq[0]);
            Assert.AreEqual(2, seq[1]);
            transactionCount = 0;
            oneTimer = null;
            Shield.InTransaction(() => {
                // if we switch the order, doesn't matter.
                transactionCount++;
                seq.Append(4);
                Assert.AreEqual(1, seq.TakeHead());
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(3);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(2, transactionCount);
            Assert.AreEqual(3, seq.Count);
            Assert.IsTrue(seq.HasAny);
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(3, seq[1]);
            Assert.AreEqual(4, seq[2]);

            Shield.InTransaction(() => { seq.Clear(); seq.Append(1); });
            Assert.AreEqual(1, seq[0]);
            transactionCount = 0;
            oneTimer = null;
            Shield.InTransaction(() => {
                // here the removal takes out the last element in the list. this cannot
                // commute, because it read from the only element's Next field, and the Seq
                // knew that it was the last element. it must conflict.
                transactionCount++;
                Assert.AreEqual(1, seq.TakeHead());
                seq.Append(3);
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(2);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(2, transactionCount);
            Assert.AreEqual(2, seq.Count);
            Assert.IsTrue(seq.HasAny);
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(3, seq[1]);

            // it is not allowed to read another Shielded from a Shielded.Commute()!
            // this greatly simplifies things. if you still want to use a value from another
            // Shielded, you must read it in main trans, forcing it's commutes to degenerate.

            var a = new Shielded<int>();
            var b = new Shielded<int>();
            try
            {
                Shield.InTransaction(() => {
                    a.Commute((ref int n) => n = 1);
                    b.Commute((ref int n) => n = a);
                });
                Assert.Fail();
            }
            catch (InvalidOperationException) {}

            try
            {
                Shield.InTransaction(() => {
                    a.Commute((ref int n) => n = 1);
                    b.Commute((ref int n) => { n = 1; a.Commute((ref int n2) => n2 = 2); });
                });
                Assert.Fail();
            }
            catch (InvalidOperationException) {}

            Shield.InTransaction(() => {
                a.Commute((ref int n) => n = 1);
                b.Commute((ref int n) => n = a);
                try
                {
                    var x = b.Read;
                    Assert.Fail();
                }
                catch (InvalidOperationException) {}
            });
        }
Beispiel #20
0
        public static void TimeTests()
        {
            var randomizr = new Random();
            int transactionCounter;
            int sleepTime = 1;
            int taskCount = 10000;

            // a little warm up for Shielded
            var warmUp = new Shielded<int>();
            Shield.InTransaction(() => warmUp.Value = warmUp + 1);

            foreach (var i in Enumerable.Repeat(0, 5))
            {
                var x = new int[100];
                transactionCounter = 0;
                var time = mtTest("dirty write", taskCount, _ =>
                {
                    var rnd = randomizr.Next(100);
                    return Task.Factory.StartNew(() =>
                    {
                        Interlocked.Increment(ref transactionCounter);
                        int v = x[rnd];
                        if (sleepTime > 0) Thread.Sleep(sleepTime);
                        x[rnd] = v + 1;
                    },
                    sleepTime > 0 ? TaskCreationOptions.LongRunning : TaskCreationOptions.None
                    );
                });
                var correct = x.Sum() == taskCount;
                Console.WriteLine(" {0} ms with {1} iterations and is {2}.",
                    time, transactionCounter, correct ? "correct" : "incorrect");
            }

            var lockCount = 100;
            foreach (var i in Enumerable.Repeat(0, 5))
            {
                var x = new int[100];
                transactionCounter = 0;
                var l = Enumerable.Repeat(0, lockCount).Select(_ => new object()).ToArray();
                var time = mtTest(string.Format("{0} lock write", lockCount), taskCount, _ =>
                {
                    var rnd = randomizr.Next(100);
                    return Task.Factory.StartNew(() =>
                    {
                        lock (l[rnd % lockCount])
                        {
                            Interlocked.Increment(ref transactionCounter);
                            int v = x[rnd];
                            if (sleepTime > 0) Thread.Sleep(sleepTime);
                            x[rnd] = v + 1;
                        }
                    },
                    sleepTime > 0 ? TaskCreationOptions.LongRunning : TaskCreationOptions.None
                    );
                });
                var correct = x.Sum() == taskCount;
                Console.WriteLine(" {0} ms with {1} iterations and is {2}.",
                    time, transactionCounter, correct ? "correct" : "incorrect");
            }

            foreach (var i in Enumerable.Repeat(0, 5))
            {
                var shx = Enumerable.Repeat(0, 100).Select(n => new Shielded<int>(n)).ToArray();
                transactionCounter = 0;
                var time = mtTest("shielded2 write", taskCount, _ =>
                {
                    var rnd = randomizr.Next(100);
                    return Task.Factory.StartNew(() =>
                    {
                        Shield.InTransaction(() =>
                        {
                            Interlocked.Increment(ref transactionCounter);
                            int v = shx[rnd];
                            if (sleepTime > 0) Thread.Sleep(sleepTime);
                            shx[rnd].Value = v + 1;
                        });
                    },
                    sleepTime > 0 ? TaskCreationOptions.LongRunning : TaskCreationOptions.None
                    );
                });
                var correct = shx.Sum(s => s.Value) == taskCount;
                Console.WriteLine(" {0} ms with {1} iterations and is {2}.",
                    time, transactionCounter, correct ? "correct" : "incorrect");
            }
        }
Beispiel #21
0
        public void Prioritization()
        {
            var x = new Shielded <int>();

            var barrier = new Barrier(2);

            int slowThread1Repeats = 0;
            var slowThread1        = new Thread(() => {
                barrier.SignalAndWait();
                Shield.InTransaction(() => {
                    Interlocked.Increment(ref slowThread1Repeats);
                    int a = x;
                    Thread.Sleep(100);
                    x.Value = a - 1;
                });
            });

            slowThread1.Start();

            IDisposable conditional = null;

            conditional = Shield.Conditional(() => { int i = x; return(true); },
                                             () => {
                barrier.SignalAndWait();
                Thread.Yield();
                conditional.Dispose();
            });

            foreach (int i in Enumerable.Range(1, 1000))
            {
                Shield.InTransaction(() => {
                    x.Modify((ref int a) => a++);
                });
            }
            slowThread1.Join();

            Assert.Greater(slowThread1Repeats, 1);
            Assert.AreEqual(999, x);

            // now, we introduce prioritization.
            // this condition gets triggered before any attempt to write into x
            int ownerThreadId = -1;

            Shield.PreCommit(() => { int a = x; return(true); }, () => {
                var threadId = ownerThreadId;
                if (threadId > -1 && threadId != Thread.CurrentThread.ManagedThreadId)
                {
                    // we'll cause lower prio threads to busy wait. we could also
                    // add, e.g., an onRollback SideEffect which would wait for
                    // a certain signal before continuing the next iteration..
                    // (NB that Shield.SideEffect would, of course, have to be called
                    // before calling Rollback.)
                    Shield.Rollback();
                }
            });

            // this will pass due to ownerThreadId == -1
            Shield.InTransaction(() => x.Value = 0);

            int slowThread2Repeats = 0;
            var slowThread2        = new Thread(() => {
                try
                {
                    barrier.SignalAndWait();
                    Interlocked.Exchange(ref ownerThreadId, Thread.CurrentThread.ManagedThreadId);
                    Shield.InTransaction(() => {
                        Interlocked.Increment(ref slowThread2Repeats);
                        int a = x;
                        Thread.Sleep(100);
                        x.Value = a - 1;
                    });
                }
                finally
                {
                    Interlocked.Exchange(ref ownerThreadId, -1);
                }
            });

            slowThread2.Start();

            conditional = Shield.Conditional(() => { int i = x; return(true); },
                                             () => {
                barrier.SignalAndWait();
                conditional.Dispose();
            });

            foreach (int i in Enumerable.Range(1, 1000))
            {
                Shield.InTransaction(() => {
                    x.Modify((ref int a) => a++);
                });
            }
            slowThread2.Join();

            Assert.AreEqual(1, slowThread2Repeats);
            Assert.AreEqual(999, x);
        }
Beispiel #22
0
        public void TransactionSafetyTest()
        {
            Shielded<int> a = new Shielded<int>(5);
            Assert.AreEqual(5, a);

            try
            {
                a.Modify((ref int n) => n = 10);
                Assert.Fail();
            }
            catch (InvalidOperationException) {}

            Assert.IsFalse(Shield.IsInTransaction);
            Shield.InTransaction(() =>
            {
                a.Modify((ref int n) => n = 20);
                // the TPL sometimes executes tasks on the same thread.
                int x1 = 0;
                var t = new Thread(() =>
                {
                    Assert.IsFalse(Shield.IsInTransaction);
                    x1 = a;
                });
                t.Start();
                t.Join();

                Assert.IsTrue(Shield.IsInTransaction);
                Assert.AreEqual(5, x1);
                Assert.AreEqual(20, a);
            });
            Assert.IsFalse(Shield.IsInTransaction);

            int x2 = 0;
            var t2 = new Thread(() =>
            {
                Assert.IsFalse(Shield.IsInTransaction);
                x2 = a;
            });
            t2.Start();
            t2.Join();
            Assert.AreEqual(20, x2);
            Assert.AreEqual(20, a);
        }
Beispiel #23
0
 private static void DictionaryTest()
 {
     var dict = new ShieldedDictNc<int, Shielded<int>>();
     var randomizr = new Random();
     while (true)
     {
         var transactionCounter = 0;
         var time = mtTest("dictionary", 10000, i =>
         {
             var rnd = randomizr.Next(10);
             if (i % 2 == 0)
                 // adder task - 500 of these
                 return Task.Factory.StartNew(() =>
                 {
                     Shield.InTransaction(() =>
                     {
                         Interlocked.Increment(ref transactionCounter);
                         var v = dict.ContainsKey(rnd) ? dict[rnd] : null;
                         int? num = v != null ? (int?)v.Value : null;
                         Thread.Sleep(1);
                         if (v == null)
                             dict[rnd] = new Shielded<int>(1);
                         else if (v.Value == -1)
                             dict.Remove(rnd);
                         else
                             v.Modify((ref int a) => a = num.Value + 1);
                     }
                     );
                 },
                 TaskCreationOptions.LongRunning
                 );
             else
                 // subtractor task - 500 of these
                 return Task.Factory.StartNew(() =>
                 {
                     Shield.InTransaction(() =>
                     {
                         Interlocked.Increment(ref transactionCounter);
                         var v = dict.ContainsKey(rnd) ? dict[rnd] : null;
                         int? num = v != null ? (int?)v.Value : null;
                         Thread.Sleep(1);
                         if (v == null)
                             dict[rnd] = new Shielded<int>(-1);
                         else if (v.Value == 1)
                             dict.Remove(rnd);
                         else
                             v.Modify((ref int a) => a = num.Value - 1);
                     }
                     );
                 },
                 TaskCreationOptions.LongRunning
                 );
         });
         var sum = Enumerable.Range(0, 10).Sum(n => dict.ContainsKey(n) ? dict[n] : 0);
         var zeroes = Shield.InTransaction(() => dict.Any(kvp => kvp.Value == 0));
         Console.WriteLine(" {0} ms with {1} iterations and sum {2}, {3}",
             time, transactionCounter, sum, zeroes ? "with zeroes!" : "no zeroes.");
     }
 }
Beispiel #24
0
        public void ComplexCommute()
        {
            // some more complex commute combinations. first, with ShieldedSeq ops.
            var seq = new ShieldedSeq <int>();

            // just a test for proper commute ordering
            Shield.InTransaction(() => {
                seq.Append(1);
                seq.Append(2);
                seq.Append(3);
                seq.Remove(2);
                Assert.IsTrue(seq.Any());
                Assert.AreEqual(2, seq.Count);
                Assert.AreEqual(1, seq[0]);
                Assert.AreEqual(3, seq[1]);
            });

            // a test for commutability of Append()
            Shield.InTransaction(() => { seq.Clear(); });
            int    transactionCount = 0;
            Thread oneTimer         = null;

            Shield.InTransaction(() => {
                transactionCount++;
                seq.Append(1);
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(2);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(1, transactionCount);
            Assert.AreEqual(2, seq.Count);
            // the "subthread" commited the append first, so:
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(1, seq[1]);
            Assert.IsTrue(seq.Any());

            // test for a commute degeneration - reading the head of a list causes
            // appends done in the same transaction to stop being commutable. for
            // simplicity - you could continue from the head on to the tail, and it cannot
            // thus be a commute, you read it. it could, of course, be done that it still
            // is a commute, but that would make it pretty complicated.
            Shield.InTransaction(() => { seq.Clear(); seq.Append(1); seq.Append(2); });
            Assert.AreEqual(1, seq[0]);
            Assert.AreEqual(2, seq[1]);
            transactionCount = 0;
            oneTimer         = null;
            Shield.InTransaction(() => {
                transactionCount++;
                Assert.AreEqual(1, seq.TakeHead());
                seq.Append(4);
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(3);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(2, transactionCount);
            Assert.AreEqual(3, seq.Count);
            Assert.IsTrue(seq.Any());
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(3, seq[1]);
            Assert.AreEqual(4, seq[2]);

            Shield.InTransaction(() => { seq.Clear(); seq.Append(1); seq.Append(2); });
            Assert.AreEqual(1, seq[0]);
            Assert.AreEqual(2, seq[1]);
            transactionCount = 0;
            oneTimer         = null;
            Shield.InTransaction(() => {
                // if we switch the order, doesn't matter.
                transactionCount++;
                seq.Append(4);
                Assert.AreEqual(1, seq.TakeHead());
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(3);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(2, transactionCount);
            Assert.AreEqual(3, seq.Count);
            Assert.IsTrue(seq.Any());
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(3, seq[1]);
            Assert.AreEqual(4, seq[2]);

            // here the removal takes out the last element in the list. this absolutely cannot
            // commute, because it read from the only element's Next field, and the Seq
            // knew that it was the last element. it must conflict.
            Shield.InTransaction(() => { seq.Clear(); seq.Append(1); });
            Assert.AreEqual(1, seq[0]);
            transactionCount = 0;
            oneTimer         = null;
            Shield.InTransaction(() => {
                transactionCount++;
                Assert.AreEqual(1, seq.TakeHead());
                seq.Append(3);
                if (oneTimer == null)
                {
                    oneTimer = new Thread(() => Shield.InTransaction(() =>
                    {
                        seq.Append(2);
                    }));
                    oneTimer.Start();
                    oneTimer.Join();
                }
            });
            Assert.AreEqual(2, transactionCount);
            Assert.AreEqual(2, seq.Count);
            Assert.IsTrue(seq.Any());
            Assert.AreEqual(2, seq[0]);
            Assert.AreEqual(3, seq[1]);


            // it is not allowed to read another Shielded from a Shielded.Commute()!
            // this greatly simplifies things. if you still want to use a value from another
            // Shielded, you must read it in main trans, forcing it's commutes to degenerate.

            var a = new Shielded <int>();
            var b = new Shielded <int>();

            Assert.Throws <InvalidOperationException>(() =>
                                                      Shield.InTransaction(() => {
                a.Commute((ref int n) => n = 1);
                b.Commute((ref int n) => n = a);
            }));

            Assert.Throws <InvalidOperationException>(() =>
                                                      Shield.InTransaction(() => {
                a.Commute((ref int n) => n = 1);
                b.Commute((ref int n) => {
                    n = 1;
                    a.Commute((ref int n2) => n2 = 2);
                });
            }));

            Shield.InTransaction(() => {
                a.Commute((ref int n) => n = 1);
                b.Commute((ref int n) => n = a);
                Assert.Throws <InvalidOperationException>(() => {
                    var x = b.Value;
                });
            });
        }
Beispiel #25
0
        public void Prioritization()
        {
            var x = new Shielded <int>();

            var barrier = new Barrier(2);

            // first, the version with no prioritization. the slow thread will repeat.
            int slowThread1Repeats = 0;
            var slowThread1        = new Thread(() => {
                barrier.SignalAndWait();
                Shield.InTransaction(() => {
                    Interlocked.Increment(ref slowThread1Repeats);
                    int a = x;
                    Thread.Sleep(100);
                    x.Value = a - 1;
                });
            });

            slowThread1.Start();

            IDisposable conditional = null;

            conditional = Shield.Conditional(() => { int i = x; return(true); },
                                             () => {
                barrier.SignalAndWait();
                Thread.Yield();
                conditional.Dispose();
            });

            foreach (int i in Enumerable.Range(1, 1000))
            {
                Shield.InTransaction(() => {
                    x.Modify((ref int a) => a++);
                });
            }
            slowThread1.Join();

            Assert.Greater(slowThread1Repeats, 1);
            Assert.AreEqual(999, x);

            // now, we introduce prioritization, using a simple lock
            var lockObj = new object();

            // this condition gets triggered just before any attempt to commit into x
            Shield.PreCommit(() => { int a = x; return(true); }, () => {
                // the simplest way to block low prio writers is just:
                //lock (lockObj) { }
                // but then the actual commit happens outside of the lock and may yet
                // cause a conflict with someone just taking the lock. still, it's safer!
                // and might be good enough for cases where a repetition won't hurt.
                bool taken     = false;
                Action release = () =>
                {
                    if (taken)
                    {
                        Monitor.Exit(lockObj);
                        taken = false;
                    }
                };
                // a bit of extra safety by using sync for the commit case.
                Shield.SyncSideEffect(release);
                Shield.SideEffect(null, release);

                Monitor.Enter(lockObj, ref taken);
            });

            // not yet locked, so this is ok.
            Shield.InTransaction(() => x.Value = 0);

            int slowThread2Repeats = 0;
            var slowThread2        = new Thread(() => {
                barrier.SignalAndWait();
                lock (lockObj)
                {
                    Shield.InTransaction(() =>
                    {
                        Interlocked.Increment(ref slowThread2Repeats);
                        int a = x;
                        Thread.Sleep(100);
                        x.Value = a - 1;
                    });
                }
            });

            slowThread2.Start();

            conditional = Shield.Conditional(() => { int i = x; return(true); }, () => {
                barrier.SignalAndWait();
                conditional.Dispose();
            });

            foreach (int i in Enumerable.Range(1, 1000))
            {
                Shield.InTransaction(() => {
                    x.Modify((ref int a) => a++);
                });
            }
            slowThread2.Join();

            Assert.AreEqual(1, slowThread2Repeats);
            Assert.AreEqual(999, x);
        }
Beispiel #26
0
        public static void MultiFieldOps()
        {
            long time;
            _timer = Stopwatch.StartNew();
            var numTrans = 100000;
            var fields = 20;

            Console.WriteLine(
                "Testing multi-field ops with {0} iterations, and nuber of fields (N) = {1}",
                numTrans, fields);

            var accessTest = new Shielded<int>[fields];
            for (int i = 0; i < fields; i++)
                accessTest[i] = new Shielded<int>();
            var dummy = new Shielded<int>();

            time = _timer.ElapsedMilliseconds;
            foreach (var k in Enumerable.Repeat(1, numTrans))
                Shield.InTransaction(() => {
                    dummy.Value = 3;
                    var a = dummy.Value;
                    dummy.Modify((ref int n) => n = 5);
                    a = dummy.Value;
                });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("WARM UP in {0} ms.", time);

            var results = new long[fields];
            foreach (var i in Enumerable.Range(0, fields))
            {
                time = _timer.ElapsedMilliseconds;
                foreach (var k in Enumerable.Repeat(1, numTrans))
                    Shield.InTransaction(() => {
                        for (int j = 0; j <= i; j++)
                            accessTest[j].Modify((ref int n) => n = 1);
                    });
                results[i] = _timer.ElapsedMilliseconds - time;
                Console.WriteLine("{0} field modifiers in {1} ms.", i + 1, results[i]);
            }
        }
Beispiel #27
0
    public void Update()
    {
        hudStuff.text = "Energy: " + jugador.getEnergy() + "\n Score: " + jugador.getScore();
        hudShadow.text = hudStuff.text;
        if (jugador.getEnergy() <= 0)
        {
            hudStuff.text = "Game Over, \n press return to continue...";
            hudShadow.text = hudStuff.text;
            gameArea.alpha--;
            projectileContainer.alpha--;
            entityContainer.alpha--;
            particleContainer.alpha--;

            if (Input.GetKeyDown(KeyCode.Return))
            {
                Game.instance.GoToPage(PageType.MainMenuPage);
            }

            return;
        }

        for (int x = enemies.Count - 1; x >= 0; x--)
        {
            enemies[x].Update();
            if (enemies[x].getEnergy() < 0)
            {
                entityContainer.RemoveChild(enemies[x]);
                enemies.RemoveAt(x);
            }
        }

        for (int x = projectiles.Count-1; x >= 0; x-- )
        {
            projectiles[x].Update();
            for (int w = enemies.Count - 1; w >= 0; w--)
            {
                if (projectiles[x].sprite.localRect.CloneAndOffset(projectiles[x].x,projectiles[x].y).CheckIntersect(enemies[w].sprite.localRect.CloneAndOffset(enemies[w].x,enemies[w].y))) {
                    enemies[w].setEnergy(enemies[w].getEnergy()-projectiles[x].getEnergy());
                    jugador.AddScore(enemies[w].scoreValue);
                    projectiles[x].ttl = -2f;
                    ScreenShake(2, 3);
                    FSoundManager.PlaySound("explosion");
                }
            }
            if (projectiles[x].ttl < 0)
            {
                projectiles[x].DestroyEffect();
                projectileContainer.RemoveChild(projectiles[x]);
                projectiles.RemoveAt(x);
            }
        }

        for (int x = Enemyprojectiles.Count - 1; x >= 0; x--)
        {
            Enemyprojectiles[x].Update();
            if (Enemyprojectiles[x].sprite.localRect.CloneAndOffset(Enemyprojectiles[x].x, Enemyprojectiles[x].y).CheckIntersect(jugador.sprite.localRect.CloneAndOffset(jugador.Position.x, jugador.Position.y)))
            {
                jugador.setEnergy(jugador.getEnergy()-Enemyprojectiles[x].getEnergy());
                ScreenShake(3,10);
                Enemyprojectiles[x].ttl = -1;
                FSoundManager.PlaySound("explosion");
            }
            if (Enemyprojectiles[x].ttl < 0)
            {
                Enemyprojectiles[x].DestroyEffect();
                projectileContainer.RemoveChild(Enemyprojectiles[x]);
                Enemyprojectiles.RemoveAt(x);
            }
        }

        jugador.Update();

        if (enemies.Count < minimalEnemies)
        {
            GenerateFoe();
        }

        if(jugador.getScore()>0){
        if ((jugador.getScore() % 300) == 0) {
            Shielded shiel = new Shielded(new Vector2(jugador.GetPosition().x + UnityEngine.Random.Range(-Futile.screen.width * 2, Futile.screen.width * 2), Futile.screen.halfHeight - 20));
            enemies.Add(shiel);
            jugador.AddScore(jugador.getScore()+10);
        }

        if ((jugador.getScore() % 500) == 0)
        {
           minimalEnemies ++ ;
        }
            }
    }
Beispiel #28
0
        public static void SimpleCommuteTest()
        {
            var a = new Shielded<int>();

            Shield.InTransaction(() => a.Commute((ref int n) => n++));
            Console.WriteLine(a);

            Shield.InTransaction(() =>
            {
                Console.WriteLine(a);
                a.Commute((ref int n) => n++);
                Console.WriteLine(a);
            });
            Console.WriteLine(a);

            Shield.InTransaction(() =>
            {
                a.Commute((ref int n) => n++);
                Console.WriteLine(a);
            });
            Console.WriteLine(a);
        }
Beispiel #29
0
        public static void TreePoolTest()
        {
            int numThreads = 4;
            int numItems = 200000;
            // for some reason, if this is replaced with ShieldedDict, KeyAlreadyPresent
            // exception is thrown. under one key you can then find an entity which does
            // not have that key. complete mystery.
            var tree = new ShieldedDict<Guid, TreeItem>();
            var barrier = new Barrier(numThreads + 1);
            int reportEvery = 10000;
            Shielded<int> lastReport = new Shielded<int>(0);
            Shielded<DateTime> lastTime = new Shielded<DateTime>(DateTime.UtcNow);

            Shield.Conditional(() => tree.Count >= lastReport + reportEvery, () =>
            {
                DateTime newNow = DateTime.UtcNow;
                int count = tree.Count;
                int speed = (count - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds;
                lastTime.Assign(newNow);
                lastReport.Modify((ref int n) => n += reportEvery);
                Shield.SideEffect(() =>
                {
                    Console.Write("\n{0} at {1} item/s", count, speed);
                });
                return true;
            });

            TreeItem x = new TreeItem();

            _timer = new Stopwatch();
            _timer.Start();
            var time = _timer.ElapsedMilliseconds;
            foreach (var k in Enumerable.Repeat(1, numItems))
                Shield.InTransaction(() => x.Id);
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("1 read transactions in {0} ms.", time);

            var bags = new List<Action>[numThreads];
            var threads = new Thread[numThreads];
            for (int i = 0; i < numThreads; i++)
            {
                var bag = bags[i] = new List<Action>();
                threads[i] = new Thread(() => {
                    foreach (var a in bag)
                    {
                        try
                        {
                            a();
                        }
                        catch
                        {
                            Console.Write(" * ");
                        }
                    }
                    barrier.SignalAndWait();
                });
            }

            foreach (var i in Enumerable.Range(0, numItems))
            {
                var item1 = new TreeItem();
                bags[i % numThreads].Add(() => Shield.InTransaction(() =>
                {
                    tree.Add(item1.Id, item1);
                }));
            }
            for (int i = 0; i < numThreads; i++)
                threads[i].Start();

            barrier.SignalAndWait();
            time = _timer.ElapsedMilliseconds;
            Console.WriteLine(" {0} ms.", time);

            Console.WriteLine("\nReading sequentially...");
            time = _timer.ElapsedMilliseconds;
            var keys = Shield.InTransaction(() => tree.Keys);
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Keys read in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            Shield.InTransaction(() => {
                foreach (var kvp in tree)
                    x = kvp.Value;
            });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by enumerator in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            Shield.InTransaction(() => {
                foreach (var k in keys)
                    x = tree[k];
            });
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by key in one trans in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            foreach (var k in keys)
                x = tree[k];
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by key separately in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            keys.AsParallel().ForAll(k => x = tree[k]);
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("Items read by key in parallel in {0} ms.", time);

            time = _timer.ElapsedMilliseconds;
            foreach (var k in Enumerable.Repeat(1, numItems))
                Shield.InTransaction(() => x.Id);
            time = _timer.ElapsedMilliseconds - time;
            Console.WriteLine("1 read transactions in {0} ms.", time);
        }
Beispiel #30
0
        public static void BetShopPoolTest()
        {
            int numThreads = 3;
            int numTickets = 200000;
            int numEvents = 100;
            var barrier = new Barrier(2);
            var betShop = new BetShop(numEvents);
            var randomizr = new Random();

            var bags = new List<Action>[numThreads];
            var threads = new Thread[numThreads];
            for (int i = 0; i < numThreads; i++)
            {
                var bag = bags[i] = new List<Action>();
                threads[i] = new Thread(() => {
                    foreach (var a in bag)
                        a();
                });
            }

            var complete = new Shielded<int>();
            IDisposable completeCond = null;
            completeCond = Shield.Conditional(() => complete == numTickets, () => {
                barrier.SignalAndWait();
                completeCond.Dispose();
            });

            var reportEvery = 10000;
            Shielded<int> lastReport = new Shielded<int>(0);
            Shielded<DateTime> lastTime = new Shielded<DateTime>(DateTime.UtcNow);
            using (Shield.Conditional(
                () => betShop.Tickets.Count >= lastReport + reportEvery,
                () => {
                    DateTime newNow = DateTime.UtcNow;
                    int count = betShop.Tickets.Count;
                    int speed = (count - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds;
                    lastTime.Value = newNow;
                    lastReport.Modify((ref int n) => n += reportEvery);
                    Shield.SideEffect(() =>
                            Console.Write("\n{0} at {1} item/s", count, speed));
                }))
            {
                foreach (var i in Enumerable.Range(0, numTickets))
                {
                    decimal payIn = (randomizr.Next(10) + 1m) * 1;
                    int event1Id = randomizr.Next(numEvents) + 1;
                    int event2Id = randomizr.Next(numEvents) + 1;
                    int event3Id = randomizr.Next(numEvents) + 1;
                    int offer1Ind = randomizr.Next(3);
                    int offer2Ind = randomizr.Next(3);
                    int offer3Ind = randomizr.Next(3);
                    bags[i % numThreads].Add(() => Shield.InTransaction(() => {
                        var offer1 = betShop.Events[event1Id].BetOffers[offer1Ind];
                        var offer2 = betShop.Events[event2Id].BetOffers[offer2Ind];
                        var offer3 = betShop.Events[event3Id].BetOffers[offer3Ind];
                        betShop.BuyTicket(payIn, offer1, offer2, offer3);
                        complete.Commute((ref int n) => n++);
                    }));
                }
                _timer = Stopwatch.StartNew();
                for (int i = 0; i < numThreads; i++)
                    threads[i].Start();
                barrier.SignalAndWait();
            }

            var time = _timer.ElapsedMilliseconds;
            var totalCorrect = betShop.VerifyTickets();
            Console.WriteLine(" {0} ms with {1} tickets paid in and is {2}.",
                time, betShop.Tickets.Count, totalCorrect ? "correct" : "incorrect");
        }
Beispiel #31
0
        public static void TreeTest()
        {
            int numTasks = 100000;
            int reportEvery = 1000;

            ShieldedTree<Guid, TreeItem> tree = new ShieldedTree<Guid, TreeItem>();
            int transactionCount = 0;
            Shielded<int> lastReport = new Shielded<int>(0);
            Shielded<int> countComplete = new Shielded<int>(0);
            //            Shielded<DateTime> lastTime = new Shielded<DateTime>(DateTime.UtcNow);
            //
            //            Shield.Conditional(() => countComplete >= lastReport + reportEvery, () =>
            //            {
            //                DateTime newNow = DateTime.UtcNow;
            //                int speed = (countComplete - lastReport) * 1000 / (int)newNow.Subtract(lastTime).TotalMilliseconds;
            //                lastTime.Assign(newNow);
            //                lastReport.Modify((ref int n) => n += reportEvery);
            //                int count = countComplete;
            //                Shield.SideEffect(() =>
            //                {
            //                    Console.Write("\n{0} at {1} item/s", count, speed);
            //                }
            //                );
            //                return true;
            //            }
            //            );

            if (true)
            {
                var treeTime = mtTest("tree", numTasks, i =>
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var item1 = new TreeItem();
                        Shield.InTransaction(() =>
                        {
                            //Interlocked.Increment(ref transactionCount);
                            tree.Add(item1.Id, item1);
            //                            countComplete.Commute((ref int c) => c++);
                        }
                        );
                    }
                    );
                }
                );
                Guid? previous = null;
                bool correct = true;
                Shield.InTransaction(() =>
                {
                    int count = 0;
                    foreach (var item in tree)
                    {
                        count++;
                        if (previous != null && previous.Value.CompareTo(item.Key) > 0)
                        {
                            correct = false;
                            break;
                        }
                        previous = item.Key;
                    }
                    correct = correct && (count == numTasks);
                }
                );
                Console.WriteLine("\n -- {0} ms with {1} iterations and is {2}.",
                    treeTime, transactionCount, correct ? "correct" : "incorrect");
            }

            if (true)
            {
                ShieldedDict<Guid, TreeItem> dict = new ShieldedDict<Guid, TreeItem>();
                transactionCount = 0;
                Shield.InTransaction(() =>
                {
                    countComplete.Assign(0);
                    lastReport.Assign(0);
                }
                );

                var time = mtTest("dictionary", numTasks, i =>
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var item1 = new TreeItem();
                        Shield.InTransaction(() =>
                        {
                            //Interlocked.Increment(ref transactionCount);
                            dict[item1.Id] = item1;
            //                            countComplete.Commute((ref int c) => c++);
                        }
                        );
                    }
                    );
                }
                );
                Console.WriteLine("\n -- {0} ms with {1} iterations. Not sorted.",
                time, transactionCount);
            }

            if (true)
            {
                ConcurrentDictionary<Guid, TreeItem> dict = new ConcurrentDictionary<Guid, TreeItem>();

                var time = mtTest("ConcurrentDictionary", numTasks, i =>
                {
                    return Task.Factory.StartNew(() =>
                    {
                        var item1 = new TreeItem();
                        dict[item1.Id] = item1;
                    }
                    );
                }
                );
                Console.WriteLine("\n -- {0} ms with {1} iterations. Not sorted.",
                time, numTasks);
            }
        }
Beispiel #32
0
        static void ControlledRace()
        {
            var acc1 = new Shielded<Account>(new Account()
            {
                Id = 1,
                Balance = 1000M,
                Transfers = new List<Transfer>()
            });
            var acc2 = new Shielded<Account>(new Account()
            {
                Id = 2,
                Balance = 1000M,
                Transfers = new List<Transfer>()
            });
            int transactionCount = 0;

            mtTest("controlled race", 20, n =>
            {
                if (n % 2 == 0)
                    return Task.Factory.StartNew(() =>
                    {
                        Shield.InTransaction(() =>
                        {
                            Interlocked.Increment(ref transactionCount);
                            Shield.SideEffect(() => Console.WriteLine("Transferred 100.00 .. acc1 -> acc2"),
                                () => Console.WriteLine("Task 1 rollback!"));
                            acc1.Modify((ref Account a) =>
                            {
                                a.Balance = a.Balance - 100M;
                                var list = a.Transfers;
                                Shield.SideEffect(() => list.Add(
                                    new Transfer() { OtherId = acc2.Value.Id, AmountReceived = -100M }));
                            });
                            Thread.Sleep(100);
                            acc2.Modify((ref Account a) =>
                            {
                                a.Balance = a.Balance + 100M;
                                var list = a.Transfers;
                                Shield.SideEffect(() => list.Add(
                                    new Transfer() { OtherId = acc1.Value.Id, AmountReceived = 100M }));
                            });
                        });
                    }, TaskCreationOptions.LongRunning);
                else
                    return Task.Factory.StartNew(() =>
                    {
                        Shield.InTransaction(() =>
                        {
                            Interlocked.Increment(ref transactionCount);
                            Shield.SideEffect(() => Console.WriteLine("Transferred 200.00 .. acc1 <- acc2"),
                                () => Console.WriteLine("Task 2 rollback!"));
                            acc2.Modify((ref Account a) =>
                            {
                                a.Balance = a.Balance - 200M;
                                var list = a.Transfers;
                                Shield.SideEffect(() => list.Add(
                                    new Transfer() { OtherId = acc1.Value.Id, AmountReceived = -200M }));
                            });
                            Thread.Sleep(250);
                            acc1.Modify((ref Account a) =>
                            {
                                a.Balance = a.Balance + 200M;
                                var list = a.Transfers;
                                Shield.SideEffect(() => list.Add(
                                    new Transfer() { OtherId = acc2.Value.Id, AmountReceived = 200M }));
                            });
                        });
                    }, TaskCreationOptions.LongRunning);
            });
            Console.WriteLine("\nCompleted 20 transactions in {0} total attempts.", transactionCount);
            Console.WriteLine("Account 1 balance: {0}", acc1.Value.Balance);
            foreach (var t in acc1.Value.Transfers)
            {
                Console.WriteLine("  {0:####,00}", t.AmountReceived);
            }
            Console.WriteLine("\nAccount 2 balance: {0}", acc2.Value.Balance);
            foreach (var t in acc2.Value.Transfers)
            {
                Console.WriteLine("  {0:####,00}", t.AmountReceived);
            }
        }
Beispiel #33
0
        public void ConditionalTest()
        {
            var x              = new Shielded <int>();
            var testCounter    = 0;
            var triggerCommits = 0;

            Shield.Conditional(() => {
                Interlocked.Increment(ref testCounter);
                return(x > 0 && (x & 1) == 0);
            },
                               () => {
                Shield.SideEffect(() =>
                                  Interlocked.Increment(ref triggerCommits));
                Assert.IsTrue(x > 0 && (x & 1) == 0);
            });

            const int count = 1000;

            ParallelEnumerable.Repeat(1, count).ForAll(i =>
                                                       Shield.InTransaction(() => x.Modify((ref int n) => n++)));

            // one more, for the first call to Conditional()! btw, if this conditional were to
            // write anywhere, he might conflict, and an interlocked counter would give more due to
            // repetitions. so, this confirms reader progress too.
            Assert.AreEqual(count + 1, testCounter);
            // every change triggers it, but by the time it starts, another transaction might have
            // committed, so this is not a fixed number.
            Assert.Greater(triggerCommits, 0);


            // a conditional which does not depend on any Shielded is not allowed!
            int a = 5;

            Assert.Throws <InvalidOperationException>(() =>
                                                      Shield.Conditional(() => a > 10, () => { }));

            bool firstTime = true;
            var  x2        = new Shielded <int>();

            // this one succeeds in registering, but fails as soon as it gets triggered, due to changing it's
            // test's access pattern to an empty set.
            Shield.Conditional(() => {
                if (firstTime)
                {
                    firstTime = false;
                    return(x2 == 0);
                }
                else
                {
                    // this is of course invalid, and when reaching here we have not touched any Shielded obj.
                    return(true);
                }
            }, () => { });

            try
            {
                // this will trigger the conditional
                Shield.InTransaction(() => x2.Modify((ref int n) => n++));
                Assert.Fail();
            }
            catch (AggregateException aggr)
            {
                Assert.AreEqual(1, aggr.InnerExceptions.Count);
                Assert.AreEqual(typeof(InvalidOperationException), aggr.InnerException.GetType());
            }
        }
Beispiel #34
0
 static void OneTransaction()
 {
     Shielded<int> sh = new Shielded<int>();
     Shield.InTransaction(() =>
     {
         int x = sh;
         Console.WriteLine("Value: {0}", x);
         sh.Modify((ref int a) => a = x + 1);
         Console.WriteLine("Value after increment: {0}", sh.Value);
     });
 }
Beispiel #35
0
 public void SkewWriteTest()
 {
     var cats = new Shielded<int>(1);
     var dogs = new Shielded<int>(1);
     int transactionCount = 0;
     Task.WaitAll(
         Enumerable.Range(1, 2).Select(i => Task.Factory.StartNew(() =>
             Shield.InTransaction(() =>
             {
                 Interlocked.Increment(ref transactionCount);
                 if (cats + dogs < 3)
                 {
                     Thread.Sleep(200);
                     if (i == 1)
                         cats.Modify((ref int n) => n++);
                     else
                         dogs.Modify((ref int n) => n++);
                 }
             }), TaskCreationOptions.LongRunning)).ToArray());
     Assert.AreEqual(3, cats + dogs);
     Assert.AreEqual(3, transactionCount);
 }