using NUnit.Framework; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Zenject.Tests { [TestFixture] public class ZenjectMultithreadTests { protected DiContainer Container { get; private set; } [SetUp] public void Setup() { //Ensure all the memory pools are empty before running each tests (StaticMemoryPoolRegistry.Pools as List)?.Clear(); Container = new DiContainer(); Container.BindFactory().FromPoolableMemoryPool(x => x.WithInitialSize(1000)).NonLazy(); Container.ResolveRoots(); Container.Inject(this); } public class Foo : IPoolable, IDisposable { IMemoryPool _pool; public void Dispose() { _pool.Despawn(this); } public void OnDespawned() { _pool = null; } public void OnSpawned(IMemoryPool pool) { _pool = pool; } public class Factory : PlaceholderFactory { } } [Inject] Foo.Factory m_fooFactory; [Test] public void SpawnDespawnInParallelTask() { void SpawnAndDespawn() { var foos = new List(); //spawn for(int i = 0; i < 100; i++) { foos.Add(m_fooFactory.Create()); } Thread.Sleep(100); //despawn for (int i = 0; i < foos.Count; i++) { foos[i].Dispose(); } foos.Clear(); } //Run multiple tasks var tasks = new List(); for (int i = 0; i < 8; i++) { tasks.Add(Task.Run(SpawnAndDespawn)); } Assert.DoesNotThrowAsync(async () => await Task.WhenAll(tasks)); //check pool status var pools = StaticMemoryPoolRegistry.Pools; foreach (var pool in pools) { if (pool.NumTotal != pool.NumInactive) { TestContext.Out.WriteLine( $"[POOL]Pool of type `{@pool.ItemType}` remaining {@pool.NumInactive}/{@pool.NumTotal}. Active objects: {@pool.NumActive}"); } Assert.That(pool.NumInactive, Is.GreaterThanOrEqualTo(pool.NumTotal), $"Not all pool objects of `{@pool.ItemType}` have been returned"); } } } }