public void RegisterAction(RegionSignal action) => _impl.RegisterAction(action);
public void ReadActionThreadConsumption() { // Read actions should only be triggered once for each registration. // The implementation should use an interlocked exchange to make sure other threads can't get the action. RegionHandle handle = _tracking.BeginTracking(0, PageSize); int triggeredCount = 0; int registeredCount = 0; int signalThreadsDone = 0; bool isRegistered = false; Action registerReadAction = () => { registeredCount++; handle.RegisterAction((address, size) => { isRegistered = false; Interlocked.Increment(ref triggeredCount); }); }; const int threadCount = 16; const int iterationCount = 10000; Thread[] signalThreads = new Thread[threadCount]; for (int i = 0; i < threadCount; i++) { int randSeed = i; signalThreads[i] = new Thread(() => { Random random = new Random(randSeed); for (int j = 0; j < iterationCount; j++) { _tracking.VirtualMemoryEvent((ulong)random.Next(PageSize), 4, false); } Interlocked.Increment(ref signalThreadsDone); }); } for (int i = 0; i < threadCount; i++) { signalThreads[i].Start(); } while (signalThreadsDone != -1) { if (signalThreadsDone == threadCount) { signalThreadsDone = -1; } if (!isRegistered) { isRegistered = true; registerReadAction(); } } // The action should trigger exactly once for every registration, // then we register once after all the threads signalling it cease. Assert.AreEqual(registeredCount, triggeredCount + 1); }