public void IncrementIfLessThan_ShouldDoNothingIfTheConditionFailes() { int value = 0; Assert.That(InterlockedExtensions.IncrementIfLessThan(ref value, 0) is null); Assert.That(value, Is.EqualTo(0)); }
public void IncrementIfLessThan_ShouldWorkParallelly() { int value = 0; Task[] tasks = Enumerable .Repeat(0, 5) .Select(_ => Task.Run(Increment)) .ToArray(); Assert.DoesNotThrowAsync(() => Task.WhenAll(tasks)); Assert.That(value, Is.EqualTo(5000)); void Increment() { for (int i = 0; i < 1000; i++) { InterlockedExtensions.IncrementIfLessThan(ref value, 5001); } } }
private static int FUsedTasks; // NEM globalis, leszarmazottankent ertelmezett private IReadOnlyCollection <object> Dispatch(MethodInfo ifaceMethod, params object?[] args) { // // 1) Ne generaljuk elore le az osszes delegate-et mert nem tudhatjuk h mely metodusok implementacioja // fogja hivni a Dispatch()-et (nem biztos h az osszes). // 2) Generikus argumentumot tartalmazo metodushoz amugy sem tudnank legeneralni. // Func <TInterface, object?[], object> invoke = Cache.GetOrAdd(ifaceMethod, () => ConvertToDelegate(ifaceMethod)); // // Mivel itt a lista egy korabbi allapotaval dolgozunk ezert az iteracio alatt hozzaadott gyermekeken // nem, mig eltavolitott gyermekeken meg lesz hivva a cel metodus. // ICollection <TInterface> children = FChildren.Keys; // masolat object[] result = new object[children.Count]; List <Task> boundTasks = new(); // // Cel metodus hivasa rekurzivan az osszes gyerekre. // children.ForEach((child, itemIndex) => { // // Ha van szabad Task akkor az elem es gyermekeinek feldolgozasat elinditjuk azon // int?taskIndex = InterlockedExtensions.IncrementIfLessThan(ref FUsedTasks, MaxDegreeOfParallelism); if (taskIndex is not null) { boundTasks.Add(Task.Run(() => { WriteLine($"{nameof(Dispatch)}(): traversing parallelly ({taskIndex})"); try { result[itemIndex] = invoke(child, args); } finally { Interlocked.Decrement(ref FUsedTasks); } })); } // // Kulonben helyben dolgozzuk fel // else { result[itemIndex] = invoke(child, args); } }); if (boundTasks.Any()) { Task.WaitAll(boundTasks.ToArray()); } return(result); }