|
1
|
1 #pragma once
|
|
|
2
|
|
|
3
|
|
|
4 namespace fb2k {
|
|
|
5 //! fb2k::readWriteLock: abortable readWriteLock, allowing multiple concurrent readers while not writing, or one writer while not reading. \n
|
|
|
6 //! Safe to release locks in different threads than obtained, contrary to system object such as SRW locks.
|
|
|
7 class readWriteLock {
|
|
|
8 pfc::mutex m_guard;
|
|
|
9 size_t m_readers = 0, m_writers = 0;
|
|
|
10 typedef std::shared_ptr < pfc::event> eventRef_t;
|
|
|
11 eventRef_t m_currentEvent;
|
|
|
12 public:
|
|
|
13
|
|
|
14 void shutdown() {
|
|
|
15 for (;;) {
|
|
|
16 eventRef_t waitFor;
|
|
|
17 {
|
|
|
18 PFC_INSYNC(m_guard);
|
|
|
19 if (m_readers == 0 && m_writers == 0) return;
|
|
|
20 PFC_ASSERT(m_currentEvent);
|
|
|
21 waitFor = m_currentEvent;
|
|
|
22 }
|
|
|
23 waitFor->wait_for(-1);
|
|
|
24 }
|
|
|
25 }
|
|
|
26
|
|
|
27 service_ptr beginRead(abort_callback& a) {
|
|
|
28 for (;;) {
|
|
|
29 a.check();
|
|
|
30 eventRef_t waitFor;
|
|
|
31 {
|
|
|
32 PFC_INSYNC(m_guard);
|
|
|
33 if (m_writers == 0) {
|
|
|
34 if (!m_currentEvent) m_currentEvent = std::make_shared<pfc::event>();
|
|
|
35 ++m_readers;
|
|
|
36 return fb2k::callOnRelease([this] {
|
|
|
37 PFC_INSYNC(m_guard);
|
|
|
38 PFC_ASSERT(m_currentEvent);
|
|
|
39 PFC_ASSERT(m_readers > 0 && m_writers == 0);
|
|
|
40 if (--m_readers == 0) {
|
|
|
41 m_currentEvent->set_state(true); m_currentEvent = nullptr;
|
|
|
42 }
|
|
|
43 });
|
|
|
44 }
|
|
|
45 PFC_ASSERT(m_currentEvent);
|
|
|
46 waitFor = m_currentEvent;
|
|
|
47 }
|
|
|
48 a.waitForEvent(*waitFor);
|
|
|
49 }
|
|
|
50 }
|
|
|
51 service_ptr beginWrite(abort_callback& a) {
|
|
|
52 for (;;) {
|
|
|
53 a.check();
|
|
|
54 eventRef_t waitFor;
|
|
|
55 {
|
|
|
56 PFC_INSYNC(m_guard);
|
|
|
57 if (m_readers == 0 && m_writers == 0) {
|
|
|
58 m_currentEvent = std::make_shared<pfc::event>();
|
|
|
59 ++m_writers;
|
|
|
60 return fb2k::callOnRelease([this] {
|
|
|
61 PFC_INSYNC(m_guard);
|
|
|
62 PFC_ASSERT(m_currentEvent);
|
|
|
63 PFC_ASSERT(m_readers == 0 && m_writers > 0);
|
|
|
64 if (--m_writers == 0) {
|
|
|
65 m_currentEvent->set_state(true); m_currentEvent = nullptr;
|
|
|
66 }
|
|
|
67 });
|
|
|
68 }
|
|
|
69 PFC_ASSERT(m_currentEvent);
|
|
|
70 waitFor = m_currentEvent;
|
|
|
71 }
|
|
|
72 a.waitForEvent(*waitFor);
|
|
|
73 }
|
|
|
74 }
|
|
|
75
|
|
|
76 };
|
|
|
77 }
|