public IEnumerator TestMultithreadWitTaskRoutines()
        {
            yield return(null);


            var runner = new MultiThreadRunner("TestMultithread");

            {
                var _reusableTaskRoutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
                _reusableTaskRoutine.SetEnumerator(_iterable1);
                var continuator = _reusableTaskRoutine.Start();

                while ((continuator as IEnumerator).MoveNext())
                {
                    yield return(null);
                }

                Assert.That(_iterable1.AllRight == true);

                continuator = _reusableTaskRoutine.Start(); //another start will reset the enumerator
                Assert.That(_iterable1.AllRight == false);  //did it reset?

                while ((continuator as IEnumerator).MoveNext())
                {
                    yield return(null);
                }

                Assert.That(_iterable1.AllRight == true);
            }
            runner.Dispose();
        }
Пример #2
0
        public void TestMultithreadWithPooledTasks()
        {
            using (var runner = new MultiThreadRunner("TestMultithread"))
            {
                _iterable1.Reset();

                var continuator = _iterable1.GetEnumerator().ThreadSafeRunOnSchedule(runner);

                while (continuator.MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);

                _iterable1.Reset();

                continuator = _iterable1.GetEnumerator().ThreadSafeRunOnSchedule(runner);

                while (continuator.MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);
            }
        }
        /// <summary>
        /// very naive implementation, it's boxing and allocation madness. Just for testing purposes
        /// this give a first glimpse to the powerful concept of Svelto Tasks continuation (running
        /// tasks on other runners and white their completion on the current runner)
        /// </summary>
        /// <param name="callback"></param>
        /// <returns></returns>
        IEnumerator MoreComplexEnumerator(Action <int> callback, MultiThreadRunner runner)
        {
            int i = 0;

            {
                var enumerator1 = SubEnumerator(0, 10); //naive enumerator! it allocates
                var enumerator2 = SubEnumerator(0, 10); //naive enumerator! it allocates

                //the two enumerator will run in "parallel" on the multithread runner
                //I need to use a multithread runner as these tests won't allow using the normal
                //coroutine while the syncrunner is not suitable as it forces the current task to be finished first
                //defeating the point of testing the parallelism
                //Running an enumerator from inside another enumerator is different than yielding. A yield
                //enumerator is yield on the same runner, while in this way the enumerator starts on another
                //runner. The generated continuator is a new enumerator, used to spin the current runner
                //untile the enumerators are done.
                //In a real scenario, any compatible runner can be used.
                yield return(enumerator1.RunOnScheduler(runner));

                yield return(enumerator2.RunOnScheduler(runner));

                i = (int)enumerator1.Current + (int)enumerator2.Current;
            }

            callback(i);
        }
Пример #4
0
        public void TestMultithreadQuick()
        {
            using (var runner = new MultiThreadRunner("TestMultithreadQuick", false))
            {
                var task = _iterable1.GetEnumerator().ThreadSafeRunOnSchedule(runner);

                while (task.MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);

                //do it again to test if starting another task works

                _iterable1.Reset();

                task = _iterable1.GetEnumerator().ThreadSafeRunOnSchedule(runner);

                while (task.MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);
            }
        }
Пример #5
0
        //physicScheduler -> updateScheduler -> coroutineScheduler -> lateScheduler

        internal static void KillSchedulers()
        {
            if (_multiThreadScheduler != null)
            {
                _multiThreadScheduler.Dispose();
            }
            _multiThreadScheduler = null;

#if UNITY_5 || UNITY_5_3_OR_NEWER
            if (_coroutineScheduler != null)
            {
                _coroutineScheduler.StopAllCoroutines();
            }
            if (_physicScheduler != null)
            {
                _physicScheduler.StopAllCoroutines();
            }
            if (_lateScheduler != null)
            {
                _lateScheduler.StopAllCoroutines();
            }
            if (_updateScheduler != null)
            {
                _updateScheduler.StopAllCoroutines();
            }

            _coroutineScheduler = null;
            _physicScheduler    = null;
            _lateScheduler      = null;
            _updateScheduler    = null;
#endif
        }
        public IEnumerator TestPauseAndResume()
        {
            yield return(null);

            var runner = new MultiThreadRunner("TestStopStartTaskRoutine");

            {
                var _reusableTaskRoutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
                _reusableTaskRoutine.SetEnumerator(_iterable1);
                var continuator = _reusableTaskRoutine.Start();

                DateTime then = DateTime.Now.AddSeconds(2);

                while ((continuator as IEnumerator).MoveNext() && DateTime.Now > then)
                {
                    yield return(null);

                    _reusableTaskRoutine.Pause();
                }

                Assert.That(_iterable1.AllRight == false);

                _reusableTaskRoutine.Resume();

                while ((continuator as IEnumerator).MoveNext())
                {
                    yield return(null);
                }

                Assert.That(_iterable1.AllRight == true);
            }
            runner.Dispose();
        }
Пример #7
0
        public void MultiThreadAccess()
        {
            // Test added for NH-1251
            // If one thread break the test you can see the result in the console.
            ((Logger)log.Logger).Level = log4net.Core.Level.Debug;
            MultiThreadRunner <object> .ExecuteAction[] actions = new MultiThreadRunner <object> .ExecuteAction[]
            {
                delegate(object o)
                {
                    TypeFactory.GetStringType(rnd.Next(1, 50));
                    totalCall++;
                },
                delegate(object o)
                {
                    TypeFactory.GetBinaryType(rnd.Next(1, 50));
                    totalCall++;
                },
                delegate(object o)
                {
                    TypeFactory.GetSerializableType(rnd.Next(1, 50));
                    totalCall++;
                },
                delegate(object o)
                {
                    TypeFactory.GetTypeType(rnd.Next(1, 20));
                    totalCall++;
                },
            };
            MultiThreadRunner <object> mtr = new MultiThreadRunner <object>(100, actions);

            mtr.EndTimeout = 2000;
            mtr.TimeoutBetweenThreadStart = 2;
            mtr.Run(null);
            log.DebugFormat("{0} calls", totalCall);
        }
Пример #8
0
        public void TestMultithreadWitTaskRoutines()
        {
            using (var runner = new MultiThreadRunner("TestMultithread"))
            {
                _iterable1.Reset();

                _reusableTaskRoutine.SetEnumerator(_iterable1.GetEnumerator());

                var continuator = _reusableTaskRoutine.SetScheduler(runner).ThreadSafeStart();

                while (continuator.MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);

                _iterable1.Reset();

                _reusableTaskRoutine.SetEnumerator(_iterable1.GetEnumerator());

                continuator = _reusableTaskRoutine.ThreadSafeStart();

                while (continuator.MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);
            }
        }
        public IEnumerator TestMultithreadQuick()
        {
            yield return(null);

            using (var runner = new MultiThreadRunner("TestMultithreadQuick", false))
            {
                var task = _iterable1.RunOnScheduler(runner);

                while ((task as IEnumerator).MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);

                //do it again to test if starting another task works

                _iterable1.Reset();

                task = _iterable1.RunOnScheduler(runner);

                while ((task as IEnumerator).MoveNext())
                {
                    ;
                }

                Assert.That(_iterable1.AllRight == true);
            }
        }
Пример #10
0
        public IEnumerator TestSimpleTaskRoutineStopStartWithProvider()
        {
            ValueObject result = new ValueObject();

            using (var runner = new MultiThreadRunner("TestSimpleTaskRoutineStopStartWithProvider"))
            {
                var continuator = _reusableTaskRoutine.SetScheduler(runner)
                                  .SetEnumerator(SimpleEnumeratorLong(result)).ThreadSafeStart();

                Assert.That(continuator.completed == false, "can't be completed");
                _reusableTaskRoutine.Stop();

                Thread.Sleep(500); //let's be sure it's cmompleted

                Assert.That(continuator.completed == true, "must be completed");

                continuator =
                    _reusableTaskRoutine.SetEnumeratorProvider(() => SimpleEnumerator(result))
                    .ThreadSafeStart();

                while (continuator.MoveNext())
                {
                    yield return(null);
                }
            }

            Assert.That(result.counter == 1);
        }
        //physicScheduler -> earlyScheduler -> updateScheduler -> coroutineScheduler -> lateScheduler

        internal static void KillSchedulers()
        {
            if (_multiThreadScheduler != null && multiThreadScheduler.isKilled == false)
            {
                _multiThreadScheduler.Dispose();
            }
            _multiThreadScheduler = null;

            if (_coroutineScheduler != null)
            {
                _coroutineScheduler.Dispose();
            }
            if (_updateScheduler != null)
            {
                _updateScheduler.Dispose();
            }

            _coroutineScheduler = null;
            _updateScheduler    = null;
#if UNITY_5 || UNITY_5_3_OR_NEWER && later
            if (_physicScheduler != null)
            {
                _physicScheduler.Dispose();
            }
            if (_lateScheduler != null)
            {
                _lateScheduler.Dispose();
            }

            _physicScheduler = null;
            _lateScheduler   = null;
            _earlyScheduler  = null;
#endif
        }
Пример #12
0
        void FinalizeIt()
        {
            _started = false;

            _enumeratorWrap.Completed();

            MultiThreadRunner.MemoryBarrier();
        }
        static IEnumerator NestedEnumerator(MultiThreadRunner runner)
        {
            yield return(null);

            new WaitForSecondsEnumerator(0.1f).RunOnScheduler(runner);

            yield return(null);
        }
        public IEnumerator TestEvenFancierEnumerator()
        {
            yield return(null);

            var multiThreadRunner = new MultiThreadRunner("test");

            MoreComplexEnumerator((i) => Assert.That(i, Is.EqualTo(20)), multiThreadRunner).RunOnScheduler(new SyncRunner());
            multiThreadRunner.Dispose();
        }
Пример #15
0
        //physicScheduler -> updateScheduler -> coroutineScheduler -> lateScheduler

        static StandardSchedulers()
        {
            multiThreadScheduler = new MultiThreadRunner("MultiThreadRunner", true);
#if UNITY_5 || UNITY_5_3_OR_NEWER
            coroutineScheduler = new CoroutineMonoRunner("StandardCoroutineRunner");
            physicScheduler    = new PhysicMonoRunner("StandardPhysicRunner");
            lateScheduler      = new LateMonoRunner("StandardLateRunner");
            updateScheduler    = new UpdateMonoRunner("StandardMonoRunner");
#endif
        }
Пример #16
0
    public IEnumerator TestTightMultithread()
    {
        var iterable2 = new Enumerator(100);

        using (var runner = new MultiThreadRunner("tighttest"))
        {
            var taskroutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
            taskroutine.SetEnumerator(iterable2);
            yield return(taskroutine.Start());

            Assert.That(true);
        }
    }
        public IEnumerator TestEnumeratorStartingFromEnumeratorIndipendently()
        {
            yield return(null);

            using (var runner = new MultiThreadRunner("test"))
            {
                var continuator = NestedEnumerator(runner).RunOnScheduler(runner);

                while ((continuator as IEnumerator).MoveNext())
                {
                    yield return(null);
                }
            }
        }
    public IEnumerator TestTightMultithread()
    {
        var iterable2 = new Enumerable(100);

        using (var runner = new MultiThreadRunner("tighttest"))
        {
            var taskroutine = iterable1.PrepareTaskRoutineOnSchedule(runner);

            yield return(taskroutine.Start());

            taskroutine.SetEnumerator(iterable2);
            yield return(taskroutine.Start());

            Assert.That(true);
        }
    }
        public IEnumerator TestSimpleTaskRoutineRestartsWithProvider()
        {
            yield return(null);

            var result = new ValueObject();

            var runner = new MultiThreadRunner("TestSimpleTaskRoutineStartStart");

            {
                var taskRoutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
                taskRoutine.SetEnumeratorProvider(() => SimpleEnumerator(result));

                taskRoutine.Start();
                yield return(null); //since the enumerator waits for 1 second, it shouldn't have the time to increment

                var continuation = taskRoutine.Start();

                while ((continuation as IEnumerator).MoveNext())
                {
                    yield return(null);    //now increment
                }
                Assert.That(result.counter, Is.EqualTo(1));

                taskRoutine.Start();
                yield return(null); //since the enumerator waits for 1 second, it shouldn't have the time to increment

                continuation = taskRoutine.Start();

                while ((continuation as IEnumerator).MoveNext())
                {
                    yield return(null); //now increment
                }
                Assert.That(result.counter, Is.EqualTo(2));

                taskRoutine.Start();
                yield return(null); //since the enumerator waits for 1 second, it shouldn't have the time to increment

                continuation = taskRoutine.Start();

                while ((continuation as IEnumerator).MoveNext())
                {
                    yield return(null); //now increment
                }
                Assert.That(result.counter, Is.EqualTo(3));
            }
            runner.Dispose();
        }
Пример #20
0
        public IEnumerator TestCrazyMultiThread()
        {
            ValueObject result = new ValueObject();

            using (var runner = new MultiThreadRunner("TestSimpleTaskRoutineStopStartWithProvider"))
            {
                int i = 0;
                while (i++ < 200)
                {
                    crazyEnumerator(result, runner).RunOnSchedule(new SyncRunner());

                    yield return(null);
                }
            }

            Assert.That(result.counter == 1000);
        }
Пример #21
0
        public IEnumerator TestSimpleTaskRoutineStartStart()
        {
            using (var runner = new MultiThreadRunner("TestSimpleTaskRoutineStartStart"))
            {
                ValueObject result = new ValueObject();

                var taskRoutine = _reusableTaskRoutine.SetScheduler(runner).SetEnumeratorProvider(() => SimpleEnumerator(result));
                taskRoutine.ThreadSafeStart();
                var continuator = taskRoutine.ThreadSafeStart();

                while (continuator.MoveNext())
                {
                    yield return(null);
                }

                Assert.That(result.counter == 1);
            }
        }
        public IEnumerator TestSimpleTaskRoutineStopsStartsWithProviderForPending()
        {
            yield return(null);

            ValueObject result = new ValueObject();

            var runner = new MultiThreadRunner("TestSimpleTaskRoutineStopStartWithProvider");

            {
                int index = 0;

                var _reusableTaskRoutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
                _reusableTaskRoutine.SetEnumeratorProvider(() => SimpleEnumerator(result));
                var continuator = _reusableTaskRoutine
                                  .Start(onStop: () => Interlocked.Add(ref index, 1));

                Assert.That((continuator as IEnumerator).MoveNext() == true, "can't be completed");

                runner.isPaused = true;
                _reusableTaskRoutine.Stop();

                Assert.That((continuator as IEnumerator).MoveNext() == true, "can't be completed");

                continuator = _reusableTaskRoutine.Start(onStop: () => Interlocked.Add(ref index, 1));

                runner.isPaused = false;

                while (index == 0)
                {
                    yield return(null);
                }

                while ((continuator as IEnumerator).MoveNext())
                {
                    yield return(null);
                }

                Assert.True(index == 1); //on stop is called only if explicitly stopped
            }

            runner.Dispose();

            Assert.That(result.counter, Is.EqualTo(1));
        }
        public IEnumerator TestNaiveEnumeratorsOnMultithreadedRunners()
        {
            yield return(null);

            var runner = new MultiThreadRunner("TestMultithread");

            _iterable1.Reset();

            var continuator = _iterable1.RunOnScheduler(runner);

            while ((continuator as IEnumerator).MoveNext())
            {
                yield return(null);
            }

            Assert.That(_iterable1.AllRight == true);

            runner.Dispose();
        }
        public IEnumerator TestMultithreadIntervaled()
        {
            yield return(null);

            using (var runner = new MultiThreadRunner("TestMultithreadIntervaled", 1))
            {
                var iterable1   = new Enumerator(2000);
                var taskRoutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
                taskRoutine.SetEnumerator(iterable1);

                DateTime now = DateTime.Now;
                (taskRoutine.Start() as IEnumerator).Complete();
                var seconds = (DateTime.Now - now).TotalSeconds;

                //2000 iteration * 1ms = 2 seconds
                Assert.That((int)seconds, Is.EqualTo(2));
                Assert.IsTrue(iterable1.AllRight);
            }
        }
    public IEnumerator TestMultithreadIntervaled()
    {
        using (var runner = new MultiThreadRunner("intervalTest", 1))
        {
            DateTime now = DateTime.Now;

            var task = iterable1.ThreadSafeRunOnSchedule(runner);

            while (task.MoveNext())
            {
                yield return(null);
            }

            var seconds = (DateTime.Now - now).Seconds;

            //10000 iteration * 1ms = 10 seconds

            Assert.That(iterable1.AllRight == true && seconds == 1);
        }
    }
Пример #26
0
        public void TestMultithreadIntervaled()
        {
            using (var runner = new MultiThreadRunner("TestMultithreadIntervaled", 1))
            {
                DateTime now = DateTime.Now;

                var task = _iterable1.GetEnumerator().ThreadSafeRunOnSchedule(runner);

                while (task.MoveNext())
                {
                    ;
                }

                var seconds = (DateTime.Now - now).Seconds;

                //10000 iteration * 1ms = 10 seconds

                Assert.That(_iterable1.AllRight == true && seconds == 10);
            }
        }
        public IEnumerator MultiThreadedParallelTaskCollectionRunningOnAnotherThread()
        {
            yield return(null);

            var runner = new MultiThreadRunner("MT");

            {
                var routine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);

                routine.SetEnumerator(YieldMultiThreadedParallelTaskCollection());

                var continuator = routine.Start();

                while ((continuator as IEnumerator).MoveNext() == true)
                {
                    yield return(null);
                }
            }
            runner.Dispose();
        }
        public IEnumerator TestExceptionsAreCaughtByTaskRoutines()
        {
            yield return(null);

            var runner = new MultiThreadRunner("TestStopStartTaskRoutine");

            {
                var  _reusableTaskRoutine = TaskRunner.Instance.AllocateNewTaskRoutine(runner);
                bool isCallbackCalled     = false;
                _reusableTaskRoutine.SetEnumerator(TestWithThrow());

                var continuator = _reusableTaskRoutine.Start(onFail: (e) => isCallbackCalled = true);
                while ((continuator as IEnumerator).MoveNext())
                {
                    yield return(null);
                }

                Assert.True(isCallbackCalled);
            }
            runner.Dispose();
        }
        //physicScheduler -> earlyScheduler -> updateScheduler -> coroutineScheduler -> lateScheduler

        internal static void Dispose()
        {
            if (_multiThreadScheduler != null && multiThreadScheduler.isKilled == false)
            {
                _multiThreadScheduler.Dispose();
            }
            _multiThreadScheduler = null;
#if UNITY_5 || UNITY_5_3_OR_NEWER
            _coroutineScheduler?.Dispose();
            _updateScheduler?.Dispose();
            _physicScheduler?.Dispose();
            _lateScheduler?.Dispose();
            _earlyScheduler?.Dispose();

            _coroutineScheduler = null;
            _updateScheduler    = null;
            _physicScheduler    = null;
            _lateScheduler      = null;
            _earlyScheduler     = null;
#endif
        }
        public IEnumerator TestCrazyMultiThread()
        {
            ValueObject result = new ValueObject();

            var runner = new MultiThreadRunner("TestSimpleTaskRoutineStopStartWithProvider");

            {
                int i = 0;
                while (i++ < 20)
                {
                    var continuationWrapper = crazyEnumerator(result, runner);

                    while (continuationWrapper.MoveNext() == true)
                    {
                        yield return(null);
                    }
                }
            }
            runner.Dispose();

            Assert.That(result.counter, Is.EqualTo(100));
        }
		public void MultiThreadAccess()
		{
			MultiThreadRunner<IDictionary<int, int>>.ExecuteAction[] actions =
				new MultiThreadRunner<IDictionary<int, int>>.ExecuteAction[]
					{
						delegate(IDictionary<int, int> d)
							{
								try
								{
									log.DebugFormat("T{0} Add", Thread.CurrentThread.Name);
									write++;
									d.Add(rnd.Next(), rnd.Next());
								}
								catch (ArgumentException)
								{
									// duplicated key
								}
							}, 
						delegate(IDictionary<int, int> d)
						 	{
								log.DebugFormat("T{0} ContainsKey", Thread.CurrentThread.Name);
					   		read++;
					   		d.ContainsKey(rnd.Next());
					   	}, 
						delegate(IDictionary<int, int> d)
			   	   	{
								log.DebugFormat("T{0} Remove", Thread.CurrentThread.Name);
			   	   		write++;
			   	   		d.Remove(rnd.Next());
			   	   	}, 
						delegate(IDictionary<int, int> d)
	   	   	   	{
								log.DebugFormat("T{0} TryGetValue", Thread.CurrentThread.Name);
	   	   	   		read++;
	   	   	   		int val;
	   	   	   		d.TryGetValue(rnd.Next(), out val);
	   	   	   	}, 
						delegate(IDictionary<int, int> d)
 	   	   	   	{
 	   	   	   		try
 	   	   	   		{
									log.DebugFormat("T{0} get_this[]", Thread.CurrentThread.Name);
 	   	   	   			read++;
 	   	   	   			int val = d[rnd.Next()];
 	   	   	   		}
 	   	   	   		catch (KeyNotFoundException)
 	   	   	   		{
 	   	   	   			// not foud key
 	   	   	   		}
 	   	   	   	}, 
						delegate(IDictionary<int, int> d)
 	   	   	   	{
								log.DebugFormat("T{0} set_this[]", Thread.CurrentThread.Name);
 	   	   	   		write++;
 	   	   	   		d[rnd.Next()] = rnd.Next();
 	   	   	   	},
						delegate(IDictionary<int, int> d)
							{
								log.DebugFormat("T{0} Keys", Thread.CurrentThread.Name);
								read++;
								IEnumerable<int> e = d.Keys;
							},
						delegate(IDictionary<int, int> d)
					   	{
								log.DebugFormat("T{0} Values", Thread.CurrentThread.Name);
					   		read++;
					   		IEnumerable<int> e = d.Values;
					   	}, 
						delegate(IDictionary<int, int> d)
			   	   	{
								log.DebugFormat("T{0} GetEnumerator", Thread.CurrentThread.Name);
			   	   		read++;
			   	   		foreach (KeyValuePair<int, int> pair in d)
			   	   		{
			   	   			
			   	   		}
			   	   	},
					};
			MultiThreadRunner<IDictionary<int, int>> mtr = new MultiThreadRunner<IDictionary<int, int>>(20, actions);
			IDictionary<int, int> wrapper = new ThreadSafeDictionary<int, int>(new Dictionary<int, int>());
			mtr.EndTimeout = 2000;
			mtr.Run(wrapper);
			log.DebugFormat("{0} reads, {1} writes -- elements {2}", read, write, wrapper.Count);
		}
		public void MultiThreadAccess()
		{
			// Test added for NH-1251
			// If one thread break the test you can see the result in the console.
			((Logger) log.Logger).Level = log4net.Core.Level.Debug;
			MultiThreadRunner<object>.ExecuteAction[] actions = new MultiThreadRunner<object>.ExecuteAction[]
        	{
        		delegate(object o)
        			{
        				TypeFactory.GetStringType(rnd.Next(1, 50));
        				totalCall++;
        			},
        		delegate(object o)
        			{
        				TypeFactory.GetBinaryType(rnd.Next(1, 50));
        				totalCall++;
        			},
        		delegate(object o)
        			{
        				TypeFactory.GetSerializableType(rnd.Next(1, 50));
        				totalCall++;
        			},
        		delegate(object o)
        			{
        				TypeFactory.GetTypeType(rnd.Next(1, 20));
        				totalCall++;
        			},
        	};
			MultiThreadRunner<object> mtr = new MultiThreadRunner<object>(100, actions);
			mtr.EndTimeout = 2000;
			mtr.TimeoutBetweenThreadStart = 2;
			mtr.Run(null);
			log.DebugFormat("{0} calls", totalCall);
		}
Пример #33
0
		public void MultiThreadedTransaction()
		{
			// Test added for NH-1709 (trying to recreate the issue... without luck)
			// If one thread break the test, you can see the result in the console.
			((Logger)log.Logger).Level = log4net.Core.Level.Debug;
			var actions = new MultiThreadRunner<object>.ExecuteAction[]
        	{
        		delegate(object o)
        			{
        				Can_roll_back_transaction();
        				totalCall++;
        			},
        		delegate(object o)
        			{
        				RollbackOutsideNh();
        				totalCall++;
        			},
        		delegate(object o)
        			{
        				TransactionInsertWithRollBackTask();
        				totalCall++;
        			},
						//delegate(object o)
						//  {
						//    TransactionInsertLoadWithRollBackTask();
						//    totalCall++;
						//  },
        	};
			var mtr = new MultiThreadRunner<object>(20, actions)
			          	{
			          	  EndTimeout	= 5000, TimeoutBetweenThreadStart = 5
			          	};
			mtr.Run(null);
			log.DebugFormat("{0} calls", totalCall);
		}