Skip to content

Commit 2b297a4

Browse files
author
Herbert Koelman
committed
Merge branch 'iss-65' into develop
2 parents c3509c8 + 2693cb6 commit 2b297a4

File tree

12 files changed

+308
-9
lines changed

12 files changed

+308
-9
lines changed

include/pthread/exceptions.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ namespace pthread {
8888

8989
};
9090

91+
/** throw to indicate that something went wrong with a read/write lock
92+
*/
93+
class read_write_lock_exception: public pthread_exception {
94+
public:
95+
96+
/** thrown when read_write_lock actions fail
97+
*
98+
* @param message short description
99+
* @param pthread_errno error returned by the pthread function
100+
*/
101+
explicit read_write_lock_exception( const std::string &message, const int pthread_errno = -1) ;
102+
103+
};
104+
91105
/** Condition variable exception
92106
*/
93107
class condition_variable_exception: public pthread_exception {

include/pthread/lock_guard.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ namespace pthread {
4747
*
4848
* @param m reference to a valid pthread::mutex
4949
*/
50-
explicit lock_guard(MutexType &m): _mutex(&m) {
51-
_mutex->lock();
50+
explicit lock_guard(MutexType &m){ //: _mutex(&m) {
51+
_mutex = &m ;
52+
_mutex->lock();
5253
}
5354

5455
/** The destructor release the guarded mutex.

include/pthread/pthread.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "pthread/config.h"
2222
#include "pthread/mutex.hpp"
23+
#include "pthread/read_write_lock.hpp"
2324
#include "pthread/lock_guard.hpp"
2425
#include "pthread/condition_variable.hpp"
2526
#include "pthread/thread.hpp"
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//
2+
// read_write_lock.hpp
3+
// read_write_lock
4+
//
5+
// Created by herbert koelman on 18/03/2016.
6+
//
7+
//
8+
9+
#ifndef pthread_read_write_lock_hpp
10+
#define pthread_read_write_lock_hpp
11+
12+
// must be include as first hearder file of each source code file (see IBM's
13+
// recommandation for more info p.285 §8.3.1).
14+
#include <pthread.h>
15+
16+
#include "pthread/config.h"
17+
#include "pthread/exceptions.hpp"
18+
19+
20+
namespace pthread {
21+
22+
/** \addtogroup concurrency
23+
*
24+
* @{
25+
*/
26+
27+
/** This class acquires the read lock.
28+
*
29+
* This class cannot be instaiated as it's main putpose is to implement read locks. To use a read lock create
30+
* either a read_write_lock or a write_lock.
31+
*
32+
* @author herbert koelman ([email protected])
33+
* @since v1.6.0
34+
* @see pthread::read_write_lock
35+
*/
36+
class read_lock {
37+
public:
38+
39+
/** The method apply a read lock.
40+
*
41+
* The calling thread acquires the write lock if no other thread (reader or writer) holds the read-write lock. Otherwise, the thread shall block until
42+
* it can acquire the lock. The calling thread may deadlock if at the time the call is made it holds the read-write lock (whether a read or write lock).
43+
*/
44+
void lock ();
45+
46+
/** The method shall apply a read lock, if any thread currently holds the lock (for reading or writing)
47+
* the method throws an exception.
48+
*
49+
@see lock
50+
*/
51+
void try_lock ();
52+
53+
/** release the read lock.
54+
@throw read_write_lock_exception if error conditions preventing this method to succeed.
55+
*/
56+
void unlock ();
57+
58+
59+
/**
60+
* the descructor, shall destroy the read-write lock object referenced by rwlock and release any resources used by the lock.
61+
*/
62+
virtual ~read_lock ();
63+
64+
protected:
65+
66+
/**
67+
Constructor/Desctructor
68+
69+
this constructor shall allocate any resources required to use the read-write lock referenced by rwlock and initializes the lock to an unlocked state. The read/write lock
70+
passes NULL attributes. This means default behavior.
71+
72+
@throw read_write_lock_exception if error conditions preventing this method to succeed.
73+
*/
74+
read_lock ();
75+
76+
/** read/write lock reference */
77+
pthread_rwlock_t _rwlock;
78+
};
79+
80+
/** This class acquires the read/write write lock
81+
*
82+
* @author herbert koelman ([email protected])
83+
* @since v1.6.0
84+
*/
85+
class write_lock: public read_lock {
86+
public:
87+
/** The method apply a write lock.
88+
*
89+
* The calling thread acquires the write lock if no other thread (reader or writer) holds the read-write lock. Otherwise, the thread shall block until
90+
* it can acquire the lock. The calling thread may deadlock if at the time the call is made it holds the read-write lock (whether a read or write lock).
91+
*/
92+
void lock ();
93+
94+
/** The method shall apply a write lock, if any thread currently holds the lock (for reading or writing)
95+
* the method throws an exception.
96+
*
97+
@see lock
98+
*/
99+
void try_lock ();
100+
101+
/**
102+
Constructor/Desctructor
103+
104+
this constructor shall allocate any resources required to use the read-write lock referenced by rwlock and initializes the lock to an unlocked state. The read/write lock
105+
passes NULL attributes. This means default behavior.
106+
107+
@throw read_write_lock_exception if error conditions preventing this method to succeed.
108+
*/
109+
write_lock ();
110+
111+
/**
112+
* the descructor, shall destroy the read-write lock object referenced by rwlock and release any resources used by the lock.
113+
*/
114+
virtual ~write_lock ();
115+
116+
};
117+
118+
/** A read/write lock.
119+
*
120+
* <pre><code>
121+
* ...
122+
* pthread::read_write_lock _rwlock;
123+
*
124+
* {
125+
* // get a read lock
126+
* pthread::lock_guard<pthread::read_lock> lock(_rwlck);
127+
* ...
128+
* } // lock_guard unlock lock here
129+
*
130+
* {
131+
* // get write lock
132+
* pthread::lock_guard<pthread::write_lock> lock(_rwlck);
133+
* ...
134+
* } // lock_guard unlock lock here
135+
*
136+
* </code></pre>
137+
*
138+
*/
139+
typedef write_lock read_write_lock;
140+
141+
/** @} */
142+
} // namespace pthread
143+
144+
#endif /* pthread_read_write_lock_H */

include/pthread/sync_queue.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,24 @@ namespace pthread {
8080
}
8181

8282
/** @return current number of elements in the queue */
83+
#if __cplusplus < 201103L
84+
size_t size() const {
85+
// we use read/write locks when std::atomic is not available
86+
pthread::lock_guard<pthread::read_lock> lck(_rwlock);
87+
#else
8388
size_t size() const {
89+
#endif
8490
return _items.size();
8591
}
8692

8793
/** @return maximun number of items that can be put in the queue */
94+
#if __cplusplus < 201103L
95+
size_t max_size() {
96+
// we use read/write locks when std::atomic is not available
97+
pthread::lock_guard<pthread::read_lock> lck(_rwlock);
98+
#else
8899
size_t max_size() const {
100+
#endif
89101
return _max_size ;
90102
}
91103

@@ -96,7 +108,8 @@ namespace pthread {
96108
void set_max_size( size_t ms ){
97109
if (ms > 0){
98110
#if __cplusplus < 201103L
99-
pthread::lock_guard<pthread::mutex> lck(_mutex);
111+
// we use read/write locks when std::atomic is not available
112+
pthread::lock_guard<pthread::write_lock> lck(_rwlock);
100113
#endif
101114
_max_size = ms;
102115
}else{
@@ -124,6 +137,7 @@ namespace pthread {
124137
pthread::condition_variable _not_full_cv;
125138
std::list<T> _items ;
126139
#if __cplusplus < 201103L
140+
pthread::read_write_lock _rwlock;
127141
int _max_size ;
128142
#else
129143
std::atomic<int> _max_size ;

src/exceptions.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ namespace pthread {
4747
mutex_exception::mutex_exception( const std::string &message, const int pthread_error): pthread_exception(message, pthread_error) {
4848
};
4949

50+
// read_write_lock exception -----------------------------
51+
//
52+
read_write_lock_exception::read_write_lock_exception( const std::string &message, const int pthread_error): pthread_exception(message, pthread_error) {
53+
};
54+
5055
// condition_variable_exception -----------------------------
5156
//
5257
condition_variable_exception::condition_variable_exception( const std::string &message, const int pthread_error): pthread_exception(message, pthread_error){

src/read_write_lock.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
2+
#include "pthread/read_write_lock.hpp"
3+
4+
5+
namespace pthread {
6+
7+
void write_lock::lock (){
8+
int ret = pthread_rwlock_wrlock(&_rwlock);
9+
if ( ret != 0 ){
10+
throw read_write_lock_exception("Try get write lock failed.", ret);
11+
};
12+
}
13+
14+
void write_lock::try_lock (){
15+
int ret = pthread_rwlock_trywrlock(&_rwlock);
16+
if ( ret != 0 ){
17+
throw read_write_lock_exception("Try get write lock failed.", ret);
18+
};
19+
}
20+
21+
write_lock::write_lock (){//:read_lock(){
22+
// intentional
23+
// the read/write lock is created by the base class read_lock
24+
}
25+
26+
write_lock::~write_lock(){
27+
// intentional... base class is in charge of freeing allocated ressources
28+
}
29+
30+
// read_lock -----------------------------
31+
//
32+
void read_lock::lock (){
33+
int ret = pthread_rwlock_rdlock(&_rwlock);
34+
if ( ret != 0 ){
35+
throw read_write_lock_exception("Try get read lock failed.", ret);
36+
};
37+
}
38+
39+
void read_lock::try_lock (){
40+
int ret = pthread_rwlock_tryrdlock(&_rwlock);
41+
if ( ret != 0 ){
42+
throw read_write_lock_exception("Try get read lock failed.", ret);
43+
};
44+
}
45+
46+
void read_lock::unlock (){
47+
int ret = pthread_rwlock_unlock(&_rwlock);
48+
if ( ret != 0 ){
49+
throw read_write_lock_exception("failed to unlock read/read lock.", ret);
50+
};
51+
}
52+
53+
read_lock::read_lock (){
54+
int ret = pthread_rwlock_init(&_rwlock, NULL);
55+
if ( ret != 0 ){
56+
throw read_write_lock_exception("Failed to init read/write lock", ret);
57+
};
58+
}
59+
60+
read_lock::~read_lock (){
61+
pthread_rwlock_destroy(&_rwlock);
62+
}
63+
64+
65+
/** @} */
66+
} // namespace pthread

tests/Makefile.in

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,16 @@ LDFLAGS=@LDFLAGS@
3131
LIBS=@LIBS@
3232

3333
OBJECTS=@OBJECTS@
34-
TARGETS=synchronized_queue_tests without-cpp11-pthread-tests exceptions-tests
34+
TARGETS=@TESTS@
3535

3636
all:${TARGETS}
3737

38-
clean: globber
39-
40-
globber:
41-
${RM} *.o core core.* *.a *.out
38+
clean:
39+
${RM} *.o
4240
${RM} ${TARGETS}
41+
42+
globber: clean
43+
${RM} core core.* *.a *.out
4344
$(RM) *unc-backup*~ *unc-backup*~
4445
$(RM) ULOG*
4546

tests/configure

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ ac_includes_default="\
624624

625625
ac_subst_vars='LTLIBOBJS
626626
LIBOBJS
627+
TESTS
627628
OBJECTS
628629
BITS
629630
EGREP
@@ -3671,6 +3672,15 @@ done
36713672
OBJECTS=$OBJECTS
36723673

36733674

3675+
TESTS=""
3676+
for src in *tests.cpp
3677+
do
3678+
obj=`basename $src .cpp`
3679+
TESTS="$TESTS $obj"
3680+
done
3681+
TESTS=$TESTS
3682+
3683+
36743684
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for specific $CXX compiler options" >&5
36753685
$as_echo_n "checking for specific $CXX compiler options... " >&6; }
36763686
case "$CXX" in

tests/configure.ac

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ do
3636
done
3737
AC_SUBST(OBJECTS,$OBJECTS)
3838

39+
TESTS=""
40+
for src in *tests.cpp
41+
do
42+
obj=`basename $src .cpp`
43+
TESTS="$TESTS $obj"
44+
done
45+
AC_SUBST(TESTS,$TESTS)
46+
3947
AC_MSG_CHECKING([for specific $CXX compiler options])
4048
case "$CXX" in
4149
xlC_r | xlC)

0 commit comments

Comments
 (0)