It's just terrible. A kernel-space sync primitive that actually sleeps the threads during contention is necessary
Once first thread is done, it signals the event with Set() and then nulls the field.
Further attempts to enter only cost an interlocked increment and regular read.
Is the ownerThreadID field write not done yet or not visible to other threads/CPUs yet? No biggie, it really only needs validity on the thread that got the lock so as to support reentrancy.
Importantly, the ManualResetEvent is NOT disposed. GC must clean up.
Polygons need clipping, combining, transforming. Text needs layout. Brushes need to be loaded, rendered. etc
Also I made a mistake in my paste: Enter() and Exit() should not have 'override'. In my code base, the class derives from a base CriticalSection class.