libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNRWLock.cpp
Go to the documentation of this file.
1 /* Copyright 2011-2012 CoReNum, INSA-Lyon
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNRWLock.cpp
19  * \author Yann LEYDIER
20  */
21 
22 #include <CRNUtils/CRNRWLock.h>
23 #ifdef _MSC_VER
24 # include <windows.h>
25 #else
26 # include <pthread.h>
27 #endif
28 
29 using namespace crn;
30 
32 {
33 #ifdef _MSC_VER
34  bool wrpriority; // true, if writer priority
35  DWORD rdcount; // number of active readers
36  DWORD rdwaiting; // number of waiting readers
37  DWORD wrcount; // number of active writers
38  DWORD wrwaiting; // number of waiting writers
39  HANDLE rdgreen, wrgreen; // reader and writer events
40  CRITICAL_SECTION rwcs; // R/W lock critical section
41 #else
42  pthread_rwlock_t rwlock;
43 #endif
44 };
45 
48  data(std::make_unique<internal_data>())
49 {
50 #ifdef _MSC_VER
51  data->wrpriority = true; // XXX
52  data->rdcount = data->rdwaiting = data->wrcount = data->wrwaiting = 0;
53  InitializeCriticalSection(&(data->rwcs));
54  data->rdgreen = CreateEvent(nullptr, FALSE, TRUE, nullptr);
55  data->wrgreen = CreateEvent(nullptr, FALSE, TRUE, nullptr);
56 #else
57  pthread_rwlock_init(&(data->rwlock), nullptr);
58 #endif
59 }
60 
63 {
64 #ifdef _MSC_VER
65  CloseHandle(data->rdgreen);
66  CloseHandle(data->wrgreen);
67  DeleteCriticalSection(&(data->rwcs));
68 #else
69  pthread_rwlock_destroy(&(data->rwlock));
70 #endif
71 }
72 
75 {
76 #ifdef _MSC_VER
77  bool wait = false;
78  do
79  {
80  EnterCriticalSection(&(data->rwcs));
81  //
82  // acquire lock if
83  // - there are no active writers and
84  // - readers have priority or
85  // - writers have priority and there are no waiting writers
86  //
87  if (!data->wrcount && (!data->wrpriority || !data->wrwaiting))
88  {
89  if (wait)
90  {
91  data->rdwaiting -= 1;
92  wait = false;
93  }
94  data->rdcount += 1;
95  }
96  else
97  {
98  if (!wait)
99  {
100  data->rdwaiting += 1;
101  wait = true;
102  }
103  // always reset the event to avoid 100% CPU usage
104  ResetEvent(data->rdgreen);
105  }
106 
107  LeaveCriticalSection(&(data->rwcs));
108 
109  if (wait)
110  {
111  WaitForSingleObject(data->rdgreen, INFINITE);
112  }
113 
114  } while(wait);
115 #else
116  pthread_rwlock_rdlock(&(data->rwlock));
117 #endif
118 }
119 
122 {
123 #ifdef _MSC_VER
124  EnterCriticalSection(&(data->rwcs));
125  data->rdcount -= 1;
126 
127  // always release waiting threads (do not check for rdcount == 0)
128  if (data->wrpriority)
129  {
130  if (data->wrwaiting)
131  SetEvent(data->wrgreen);
132  else if(data->rdwaiting)
133  SetEvent(data->rdgreen);
134  }
135  else
136  {
137  if(data->rdwaiting)
138  SetEvent(data->rdgreen);
139  else if(data->wrwaiting)
140  SetEvent(data->wrgreen);
141  }
142  LeaveCriticalSection(&(data->rwcs));
143 #else
144  pthread_rwlock_unlock(&(data->rwlock));
145 #endif
146 }
147 
150 {
151 #ifdef _MSC_VER
152  bool wait = false;
153  do
154  {
155  EnterCriticalSection(&(data->rwcs));
156  //
157  // acquire lock if
158  // - there are no active readers nor writers and
159  // - writers have priority or
160  // - readers have priority and there are no waiting readers
161  //
162  if (!data->rdcount && !data->wrcount && (data->wrpriority || !data->rdwaiting))
163  {
164  if (wait)
165  {
166  data->wrwaiting -= 1;
167  wait = false;
168  }
169  data->wrcount++;
170  }
171  else
172  {
173  if(!wait)
174  {
175  data->wrwaiting += 1;
176  wait = true;
177  }
178  // always reset the event to avoid 100% CPU usage
179  ResetEvent(data->wrgreen);
180  }
181 
182  LeaveCriticalSection(&(data->rwcs));
183 
184  if (wait)
185  {
186  WaitForSingleObject(data->wrgreen, INFINITE);
187  }
188  } while (wait);
189 #else
190  pthread_rwlock_wrlock(&(data->rwlock));
191 #endif
192 }
193 
196 {
197 #ifdef _MSC_VER
198  EnterCriticalSection(&(data->rwcs));
199  data->wrcount -= 1;
200  if (data->wrpriority)
201  {
202  if (data->wrwaiting)
203  SetEvent(data->wrgreen);
204  else if (data->rdwaiting)
205  SetEvent(data->rdgreen);
206  }
207  else
208  {
209  if (data->rdwaiting)
210  SetEvent(data->rdgreen);
211  else if (data->wrwaiting)
212  SetEvent(data->wrgreen);
213  }
214  LeaveCriticalSection(&(data->rwcs));
215 #else
216  pthread_rwlock_unlock(&(data->rwlock));
217 #endif
218 }
219 
pthread_rwlock_t rwlock
Definition: CRNRWLock.cpp:42
void WriteUnlock()
Releases write token.
Definition: CRNRWLock.cpp:195
RWLock()
Constructor.
Definition: CRNRWLock.cpp:47
~RWLock()
Destructor.
Definition: CRNRWLock.cpp:62
void WaitWriteLock()
Requests authorization to write.
Definition: CRNRWLock.cpp:149
void WaitReadLock()
Requests authorization to read.
Definition: CRNRWLock.cpp:74
#define TRUE
Definition: CRNProp3.cpp:28
void ReadUnlock()
Releases read token.
Definition: CRNRWLock.cpp:121