1: public class StateReaderWriterLock : IDisposable
2: { 3: private readonly AutoResetEvent _changeStateAutoLock = new AutoResetEvent(false);
4: private readonly AutoResetEvent _writerDone = new AutoResetEvent(false);
5: private readonly object _readersLock = new object();
6: private readonly object _writersLock = new object();
7: private int _readers;
8: private int _state; // 0 is "neutral", 1 is read, 2 is write
9: private int _writers;
10:
11: public void LockReader()
12: { 13: while (true)
14: { 15: // try to bring the state from "neutral" or "read" to "read". If the current state is "write", let's wait.
16: while (Interlocked.CompareExchange(ref _state, 1, 0) == 2)
17: _changeStateAutoLock.WaitOne();
18:
19: // an interesting case here where the last reader is now in ReleaseRead and we're trying to read as well, we might be too late (the writer might have changed the _state already)
20: // if that happens - we're back to square one, but we still want to avoid recursive locking!
21: bool loseInRace = false;
22: lock (_readersLock)
23: { 24: if (Interlocked.CompareExchange(ref _state, 1, 0) == 2)
25: loseInRace = true;
26: else
27: _readers++;
28: }
29: if (!loseInRace)
30: return; // success!
31: }
32: }
33:
34: public void ReleaseReader()
35: { 36: lock (_readersLock)
37: { 38: _readers--;
39:
40: // if I am the last reader, let's reset the state so any given reader/writer can take it
41: if (_readers == 0)
42: { 43: Thread.VolatileWrite(ref _state, 0);
44: _changeStateAutoLock.Set();
45: }
46: }
47: }
48:
49: public void LockWriter()
50: { 51: while (true)
52: { 53: // try to bring the state from "neutral" or "write" to "write". If the current state is "read", let's wait.
54: while (Interlocked.CompareExchange(ref _state, 2, 0) == 1)
55: _changeStateAutoLock.WaitOne();
56:
57: bool loseInRace = false;
58: lock (_writersLock)
59: { 60: if (Interlocked.CompareExchange(ref _state, 2, 0) == 1)
61: loseInRace = true;
62: else
63: _writers++;
64: }
65:
66: if (!loseInRace)
67: break; // great success!
68: }
69:
70: // allow 1 writer only
71: if (Thread.VolatileRead(ref _writers) > 1)
72: { 73: _writerDone.WaitOne();
74: }
75: }
76:
77: public void ReleaseWriter()
78: { 79: lock (_writersLock)
80: { 81: _writers--;
82:
83: // if I am the last writer, let's reset the state so any given reader/writer can take it
84: if (_writers == 0)
85: { 86: Thread.VolatileWrite(ref _state, 0);
87: _changeStateAutoLock.Set();
88: }
89: else
90: { 91: _writerDone.Set();
92: }
93: }
94: }
95:
96: public void Dispose()
97: { 98: _changeStateAutoLock.Close();
99: _writerDone.Close();
100: }
101: }
102: