1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
/*
* Copyright (C) 2007-2014 Xagasoft, All rights reserved.
*
* This file is part of the libbu++ library and is released under the
* terms of the license contained in the file LICENSE.
*/
#ifndef BU_READ_WRITE_MUTEX_H
#define BU_READ_WRITE_MUTEX_H
#include "bu/mutex.h"
#include "bu/condition.h"
namespace Bu
{
/**
* Mutex designed for situations where overlapped reading is safe, but
* overlapped writing isn't. There are many, many good examples of this
* including most data structures, streams, etc. etc.
*
* Use this just like a normal mutex except that you use the
* lockRead/unlockRead and lockWrite/unlockWrite functions depending on
* weather the section of code your locking is reading data or changing
* data.
*
* This particular mutex is designed so that while a read operation is
* happening other read operations can also happen, but no write operations
* can occur. While a write is happening, no other write or read operation
* can continue. There is an extra feature to ensure writes get a chance
* to complete, when a lockWrite is issued, all current read operations
* continue, but future read operations block until the write is complete.
*/
class ReadWriteMutex
{
public:
ReadWriteMutex();
virtual ~ReadWriteMutex();
/**
* Lock the mutex for reading. Multiple code sections can hold a read
* lock at the same time, but write locks will wait for all read locks
* to be released before continuing. Read locks will also wait if
* there is an active write lock.
*
* It is very important to not make any changes to your data within
* a read lock.
*/
void lockRead();
/**
* Release a read lock.
*/
void unlockRead();
/**
* Lock the mutex for writing. Only one code section can have a write
* lock at any given time. No code sections can be in a locked read
* section while a write lock is held. When a write lock is requested
* all following read locks will block until the write operation is
* started, ensuring writes always get a chance to execute.
*
* Within a write locked code section feel free to change your data
* and read your data. It is imparative to spend as little time as
* possible in a write-locked section.
*/
void lockWrite();
/**
* Release a write lock.
*/
void unlockWrite();
class ReadLocker
{
public:
ReadLocker( ReadWriteMutex &m ) :
m( m )
{
m.lockRead();
}
~ReadLocker()
{
m.unlockRead();
}
private:
ReadWriteMutex &m;
};
class WriteLocker
{
public:
WriteLocker( ReadWriteMutex &m ) :
m( m )
{
m.lockWrite();
}
~WriteLocker()
{
m.unlockWrite();
}
private:
ReadWriteMutex &m;
};
private:
Bu::Mutex mRead;
int iCounter;
Bu::Mutex mWrite;
Bu::Condition cWrite;
bool bWantWrite;
};
};
#endif
|