Esempio n. 1
0
 /// <summary>Copies a specified number of items into an array.</summary>
 public void CopyTo(int sourceIndex, T[] destination, int destinationIndex, int count)
 {
     Utility.ValidateRange(Count, sourceIndex, count);
     Utility.ValidateRange(destination, destinationIndex, count);
     STM.Retry(delegate
     {
         for (int i = 0; i < count; i++)
         {
             destination[destinationIndex + i] = array[sourceIndex + i].Read();
         }
     });
 }
Esempio n. 2
0
 /// <summary>Returns the index of the first item in the given region of the array equal to the given item, or -1 if no such
 /// item could be found.
 /// </summary>
 public int IndexOf(T item, int index, int count)
 {
     Utility.ValidateRange(Count, index, count);
     return(STM.Retry(delegate
     {
         for (int end = index + count; index < end; index++)
         {
             if (comparer.Equals(item, array[index].Read()))
             {
                 return index;
             }
         }
         return -1;
     }));
 }
Esempio n. 3
0
 /// <summary>Determines whether the given item exists in a given range within the array.</summary>
 public bool Contains(T item, int index, int count)
 {
     Utility.ValidateRange(Count, index, count);
     return(STM.Retry(delegate
     {
         for (int i = index, end = index + count; i < end; i++)
         {
             if (comparer.Equals(item, array[i].Read())) // if an item is found, changes to previous items won't affect the result,
             {                                           // so we can release them to avoid false conflicts
                 while (i > index)
                 {
                     array[--i].Release();
                 }
                 return true;
             }
         }
         return false;
     }));
 }
Esempio n. 4
0
        public void T05_TestContention()
        {
            // test the EnsureConsistency option
            TransactionalVariable <int> a = STM.Allocate <int>(), b = STM.Allocate <int>();

            using (STMTransaction tx = STMTransaction.Create(STMOptions.EnsureConsistency))
            {
                Assert.IsTrue(tx.EnsureConsistency);
                a.Read();
                Assert.IsTrue(a.IsConsistent());
                Assert.IsTrue(tx.IsConsistent());
                a.CheckConsistency();
                TestHelpers.RunInAnotherThread(delegate { STM.Retry(delegate { a.Set(1); }); });
                Assert.IsFalse(a.IsConsistent());
                Assert.IsFalse(tx.IsConsistent());
                TestHelpers.TestException <TransactionAbortedException>(delegate { a.CheckConsistency(); });
                TestHelpers.TestException <TransactionAbortedException>(delegate { tx.CheckConsistency(); });
                TestHelpers.TestException <TransactionAbortedException>(delegate { b.Read(); });
            }

            const int Iterations = 500;

            TransactionalVariable <int>[] vars = new TransactionalVariable <int> [10]; // the array length must be even
            for (int i = 0; i < vars.Length; i++)
            {
                vars[i] = STM.Allocate <int>();
            }

            Random      rand      = new Random();
            Exception   exception = null;
            ThreadStart code      = delegate
            {
                try
                {
                    int index;
                    lock (rand) index = rand.Next(vars.Length); // start at a random location in each thread
                    for (int time = 0; time < Iterations; time++)
                    {
                        // create a loop that increments every variable in the array once in a series of small transactions that write
                        // two elements and read the intervening ones
                        for (int i = 0; i < vars.Length / 2; i++)
                        {
                            int origIndex = index; // store the index so we can restore it if a transaction aborts
                            STM.Retry(delegate
                            {
                                index = origIndex;
                                vars[index].Set(vars[index].OpenForWrite() + 1);
                                if (++index == vars.Length)
                                {
                                    index = 0;
                                }
                                for (int j = 0; j < vars.Length / 2 - 1; j++)
                                {
                                    vars[index].Read();
                                    if (++index == vars.Length)
                                    {
                                        index = 0;
                                    }
                                }
                                vars[index].Set(vars[index].OpenForWrite() + 1);
                                if (++index == vars.Length)
                                {
                                    index = 0;
                                }
                            });
                            origIndex = index;
                        }
                    }
                }
                catch (Exception ex) { exception = ex; }
            };

            Thread[] threads = new Thread[16];
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i] = new Thread(code);
            }
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Start();
            }
            for (int i = 0; i < threads.Length; i++)
            {
                if (!threads[i].Join(10000))
                {
                    threads[i].Abort();               // give the test 10 seconds to run
                }
            }

            if (exception != null)
            {
                throw exception;
            }

            // make sure all variables were incremented the right number of times
            for (int i = 0; i < vars.Length; i++)
            {
                Assert.AreEqual(Iterations * threads.Length, vars[i].ReadWithoutOpening());
            }
        }
Esempio n. 5
0
        public void T03_TestErrors()
        {
            // test that variables can't be created with uncloneable types
            TestHelpers.TestException <NotSupportedException>(delegate { STM.Allocate <object>(); });
            TestHelpers.TestException <NotSupportedException>(delegate { STM.Allocate <UncopyableStruct>(); });

            // test that transactions can't be committed twice
            using (STMTransaction tx = STMTransaction.Create())
            {
                tx.Commit();
                TestHelpers.TestException <InvalidOperationException>(delegate { tx.Commit(); });
            }

            // test that variables can't be opened for write outside transactions
            TransactionalVariable <int> a = STM.Allocate <int>();

            TestHelpers.TestException <InvalidOperationException>(delegate { a.OpenForWrite(); });
            TestHelpers.TestException <InvalidOperationException>(delegate { a.Set(1); });

            // test that bad implementations of ICloneable are detected
            TransactionalVariable <BadCloneable> b = STM.Allocate(new BadCloneable());

            using (STMTransaction tx = STMTransaction.Create())
            {
                TestHelpers.TestException <InvalidOperationException>(delegate { b.OpenForWrite(); });
            }

            // test that a transaction can't be committed before nested transactions have been dealt with
            using (STMTransaction otx = STMTransaction.Create())
            {
                STMTransaction tx = STMTransaction.Create();
                TestHelpers.TestException <InvalidOperationException>(delegate { otx.Commit(); });
            }

            // test that STM.Retry() fails when a transaction times out
            TestHelpers.TestException <TransactionAbortedException>(delegate
            {
                STM.Retry(25, delegate
                {
                    a.Read();
                    TestHelpers.RunInAnotherThread(delegate { STM.Retry(delegate { a.Set(a.OpenForWrite() + 1); }); });
                });
            });

            // test that STM.Retry() doesn't loop infinitely if a transaction was consistent when an exception was thrown
            TransactionalVariable <int> c = STM.Allocate(0);

            TestHelpers.TestException <ArgumentOutOfRangeException>(delegate
            {
                STM.Retry(delegate
                {
                    a.Read();
                    c.Set(42);
                    throw new ArgumentOutOfRangeException();
                });
            });
            AssertEqual(c, 0);

            // but test that STM.Retry() does retry if the transaction was inconsistent
            STM.Retry(delegate { a.Set(0); });
            bool first = true;

            STM.Retry(delegate
            {
                int aValue = a.Read();
                c.Set(42);
                if (first)
                {
                    first = false;
                    TestHelpers.RunInAnotherThread(delegate { STM.Retry(delegate { a.Set(a.OpenForWrite() + 1); }); });
                }
                if (aValue == 0)
                {
                    throw new ArgumentOutOfRangeException();
                }
            });
            AssertEqual(c, 42);
        }
Esempio n. 6
0
        public void T01_TestBasicTransactions()
        {
            TransactionalVariable <int> a = STM.Allocate(1), b = STM.Allocate(2), c = STM.Allocate(3);

            AssertEqual(a, 1, b, 2, c, 3);

            // test a simple transaction that doesn't commit
            using (STMTransaction tx = STMTransaction.Create())
            {
                a.Read();                      // open one for reading
                b.OpenForWrite();              // one for writing
                AssertEqual(a, 1, b, 2, c, 3); // and leave one unopened, and check their values

                c.Set(30);
                a.Set(10);
                AssertEqual(a, 10, b, 2, c, 30);
            }
            AssertEqual(a, 1, b, 2, c, 3); // check that the changes were reverted

            // test a transaction that does commit
            using (STMTransaction tx = STMTransaction.Create())
            {
                AssertEqual(a, 1, b, 2, c, 3); // check that the changes were reverted
                c.Set(30);
                a.Set(10);
                b.Set(20);
                tx.Commit();
                AssertEqual(a, 10, b, 20, c, 30);
            }
            AssertEqual(a, 10, b, 20, c, 30);

            // test a simple nested transaction where the inner doesn't commit
            using (STMTransaction otx = STMTransaction.Create())
            {
                a.Set(-1);
                c.Read();
                AssertEqual(a, -1, c, 30);
                using (STMTransaction tx = STMTransaction.Create())
                {
                    AssertEqual(a, -1);
                    a.Set(1);
                    b.Set(2);
                    c.Set(3);
                    AssertEqual(a, 1, b, 2, c, 3);
                }
                AssertEqual(a, -1, b, 20, c, 30);
                otx.Commit();
            }
            AssertEqual(a, -1, b, 20, c, 30);

            // test a simple nested transaction where the outer doesn't commit but the inner does
            using (STMTransaction otx = STMTransaction.Create())
            {
                a.Set(1);
                c.Read();
                AssertEqual(a, 1, c, 30);
                using (STMTransaction tx = STMTransaction.Create())
                {
                    AssertEqual(a, 1);
                    a.Set(10);
                    b.Set(-2);
                    c.Set(-3);
                    AssertEqual(a, 10, b, -2, c, -3);
                    tx.Commit();
                }
                AssertEqual(a, 10, b, -2, c, -3);
            }
            AssertEqual(a, -1, b, 20, c, 30);

            // test a simple nested transaction where both commit
            using (STMTransaction otx = STMTransaction.Create())
            {
                a.Set(1);
                b.Read();
                b.Set(-2);
                c.Read();
                AssertEqual(a, 1, b, -2, c, 30);
                using (STMTransaction tx = STMTransaction.Create())
                {
                    a.Set(-1);
                    b.Set(2);
                    c.Set(3);
                    tx.Commit();
                }
                AssertEqual(a, -1, b, 2, c, 3);
                a.Set(1);
                otx.Commit();
            }
            AssertEqual(a, 1, b, 2, c, 3);

            // test the Release() method
            using (STMTransaction tx = STMTransaction.Create())
            {
                a.Set(10); // test that releasing a written variable discards changes
                AssertEqual(a, 10);
                b.Read();  // test that releasing a read variable prevents conflicts with other transactions
                c.Read();
                TestHelpers.RunInAnotherThread(delegate { STM.Retry(delegate { b.Set(20); c.Set(30); }); });
                AssertEqual(b, 2);
                a.Release();
                b.Release();
                c.Release();
                b.Read();
                AssertEqual(a, 1, b, 20);
                tx.Commit();
            }
            AssertEqual(a, 1, b, 20, c, 30);

            // test post-commit actions
            int ntValue = 0;

            using (STMTransaction tx = STMTransaction.Create())
            {
                a.Set(10);
                tx.Commit(delegate { ntValue = 1; });
            }
            Assert.AreEqual(1, ntValue);

            // ensure they're not executed unless the top-level transaction commits
            using (STMTransaction otx = STMTransaction.Create())
                using (STMTransaction tx = STMTransaction.Create())
                {
                    a.Set(10);
                    tx.Commit(delegate { ntValue = 2; });
                }
            Assert.AreEqual(1, ntValue);

            // ensure that they're executed in the right order (innermost first) and at the right time
            using (STMTransaction otx = STMTransaction.Create())
            {
                using (STMTransaction tx = STMTransaction.Create())
                {
                    a.Set(10);
                    tx.Commit(delegate { ntValue = 2; });
                    Assert.AreEqual(1, ntValue);
                }
                Assert.AreEqual(1, ntValue);
                otx.Commit(delegate { ntValue++; });
            }
            Assert.AreEqual(3, ntValue);

            // ensure that post-commit actions given to STM.Retry() work and aren't executed multiple times if the transaction restarts
            bool first = true;

            STM.Retry(
                delegate
            {
                if (first)
                {
                    first = false;
                    throw new TransactionAbortedException();
                }
            },
                delegate { ntValue++; });
            Assert.AreEqual(4, ntValue);
        }
Esempio n. 7
0
 /// <inheritdoc/>
 public T this[int index]
 {
     get { return(array[index].Read()); }
     set { STM.Retry(delegate { array[index].Set(value); }); }
 }
Esempio n. 8
0
        public void T01_TestArray()
        {
            // test the constructor that takes a count
            Assert.AreEqual(2, new TransactionalArray <int>(2).Count);

            // test the constructor that takes a list of items
            TransactionalArray <int> array = new TransactionalArray <int>(new int[] { 0, 1, 2, 3, 4 });

            Assert.AreEqual(5, array.Count);
            for (int i = 0; i < 5; i++)
            {
                Assert.AreEqual(i, array[i]);
            }

            // ensure that the array can be changed outside a transaction
            array[0] = 5;
            Assert.AreEqual(5, array[0]);
            array[0] = 0;

            using (STMTransaction tx = STMTransaction.Create())
            {
                // test indexing
                array[2] = 42;
                Assert.AreEqual(42, array[2]);

                // test IndexOf() and Contains()
                Assert.AreEqual(2, array.IndexOf(42));
                Assert.IsTrue(array.Contains(42));
                Assert.AreEqual(-1, array.IndexOf(55));
                Assert.IsFalse(array.Contains(55));

                // test CopyTo()
                int[] extArray = new int[5];
                array.CopyTo(extArray, 0);
                for (int i = 0; i < 5; i++)
                {
                    Assert.AreEqual(i == 2 ? 42 : i, extArray[i]);
                }

                // test the enumerator
                List <int> list = new List <int>();
                foreach (int i in array)
                {
                    list.Add(i);
                }
                Assert.AreEqual(5, list.Count);
                for (int i = 0; i < 5; i++)
                {
                    Assert.AreEqual(i == 2 ? 42 : i, list[i]);
                }

                // test isolation
                TestHelpers.RunInAnotherThread(delegate { Assert.AreEqual(2, array[2]); });
                tx.Commit();
            }
            Assert.AreEqual(42, array[2]);

            // test that operations compose transactionally
            using (STMTransaction otx = STMTransaction.Create())
            {
                STM.Retry(delegate { array[2] = 2; });
                STM.Retry(delegate { array[0] = -1; });
                Assert.AreEqual(-1, array[0]);
                Assert.AreEqual(2, array[2]);
                TestHelpers.RunInAnotherThread(delegate
                {
                    Assert.AreEqual(0, array[0]);
                    Assert.AreEqual(42, array[2]);
                });
                otx.Commit();
            }
            Assert.AreEqual(-1, array[0]);
            Assert.AreEqual(2, array[2]);

            // test array enlarging
            array.Enlarge(0);              // test that the array can't be shrunk
            Assert.AreEqual(5, array.Count);
            array.Enlarge(6);              // test that it can be enlarged
            Assert.AreEqual(6, array.Count);
            Assert.AreEqual(-1, array[0]); // test that enlarging it doesn't change any values
            Assert.AreEqual(2, array[2]);
        }