Skip to content

Commit 2b029ca

Browse files
refs #174 #175 #177 #178 @4h
1 parent 4224306 commit 2b029ca

File tree

9 files changed

+135
-62
lines changed

9 files changed

+135
-62
lines changed

include/pthread/mutex.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ namespace pthread {
4646
void lock();
4747

4848
/**
49-
* The function pthread_mutex_trylock is identical to pthread_mutex_lock except that
50-
* if the mutex object referenced by mutex is currently locked (by any thread,
51-
* including the current thread), the call returns immediately.
49+
* Identical to lock method except that if the mutex object is currently locked (by any thread, including the
50+
* current thread), the call returns immediately.
5251
*
53-
* @return
52+
* @return true if the mutex is locked, false is returned if the lock is held by some other thread.
5453
* @throw mutex_exception if error conditions preventing this method to succeed.
5554
* @see lock
55+
* @see unlock
5656
*/
5757
bool try_lock();
5858

include/pthread/thread.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace pthread {
150150
*
151151
* @return the stack size in bytes.
152152
*/
153-
size_t stact_size();
153+
size_t stack_size();
154154

155155
/** copy operator is flagged deleted, copying doesn't make sense
156156
*/
@@ -264,8 +264,7 @@ namespace pthread {
264264
/** @return true if this thread can be joined.
265265
*/
266266
bool joinable() const;
267-
268-
267+
269268
/** not copy-assignable */
270269
void operator=(const abstract_thread &) = delete;
271270

src/condition_variable.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,21 @@ namespace pthread {
5050
#else
5151
void condition_variable::notify_one() noexcept {
5252
#endif
53-
pthread_cond_signal ( &_condition );
53+
int rc = pthread_cond_signal ( &_condition );
54+
if ( rc != 0 ){
55+
throw condition_variable_exception{"notify_all failed.", rc};
56+
}
5457
}
5558

5659
#if __cplusplus < 201103L
5760
void condition_variable::notify_all () throw(){
5861
#else
5962
void condition_variable::notify_all () noexcept{
6063
#endif
61-
pthread_cond_broadcast ( &_condition );
62-
64+
int rc = pthread_cond_broadcast ( &_condition );
65+
if ( rc != 0 ){
66+
throw condition_variable_exception{"notify_all failed.", rc};
67+
}
6368
}
6469

6570
void condition_variable::milliseconds(int millis){

src/mutex.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ namespace pthread {
3434

3535
auto rc = pthread_mutex_trylock(&_mutex);
3636
if (rc == 0) {
37-
status = true;
37+
status = true; // mutex is locked now
38+
}else if ( rc == EBUSY){
39+
status = false ; // mutex is held by some other thread
3840
} else {
3941
throw mutex_exception("pthread_mutex_trylock failed, already locked.", rc);
4042
}

src/thread.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ namespace pthread {
148148
_attr_ptr = &_attr; // pthread_attribute is always initialized
149149
}
150150

151-
size_t thread::stact_size() {
151+
size_t thread::stack_size() {
152152
size_t size = -1;
153153
int rc = pthread_attr_getstacksize(_attr_ptr, &size);
154154
if ( rc != 0 ){
@@ -174,11 +174,13 @@ namespace pthread {
174174
}
175175

176176
void abstract_thread::join() {
177-
_thread->join();
177+
if ( _thread != nullptr ){
178+
_thread->join();
179+
}
178180
};
179181

180182
bool abstract_thread::joinable() const {
181-
return _thread != 0 && _thread->joinable();
183+
return _thread != nullptr && _thread->joinable();
182184
};
183185

184186
#if __cplusplus < 201103L

tests/abstract_thread_tests.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ TEST(absttract_thread, self_join) {
7777
TEST(abstract_thread_group, start_auto_join) {
7878
pthread::thread_group threads{true};
7979

80+
EXPECT_TRUE(threads.destructor_joins_first());
81+
8082
for (auto x = 10; x > 0; x--) {
8183
threads.add(new test_thread{});
8284
}

tests/concurrency_tests.cpp

Lines changed: 84 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,52 +10,88 @@
1010
#include <memory>
1111
#include <ctime>
1212

13+
class concurrency_test_runnable : public pthread::abstract_thread {
14+
public:
15+
16+
void run() noexcept override {
17+
pthread::lock_guard<pthread::mutex> lock{*_mutex};
18+
pthread::this_thread::sleep_for(2 * 1000);
19+
}
20+
21+
concurrency_test_runnable(pthread::mutex *mutex) : _something{0}, _mutex{mutex} {
22+
// intentional
23+
}
24+
25+
void set_something(const int something){
26+
pthread::lock_guard<pthread::write_lock> lock(_properties_accessor_lock);
27+
_something = something;
28+
}
29+
30+
const int something(){
31+
pthread::lock_guard<pthread::read_lock> lock(_properties_accessor_lock);
32+
return _something;
33+
}
34+
35+
private:
36+
37+
int _something;
38+
pthread::mutex *_mutex;
39+
pthread::read_write_lock _properties_accessor_lock;
40+
};
41+
1342
TEST(concurrency, mutex) {
1443

15-
bool success = false;
44+
bool success = false;
1645

17-
pthread::mutex mutex;
18-
try {
19-
pthread::lock_guard<pthread::mutex> lock(mutex);
20-
success = true;
21-
} catch ( std::exception &err) {
22-
std::cerr << "something went wrong: " << err.what() << std::endl;
23-
}catch ( ... ){
24-
std::cerr << "something went wrong, unexpected exception catched."<< std::endl;
25-
}
46+
pthread::mutex mutex;
47+
concurrency_test_runnable mtr{&mutex};
48+
mtr.start();
2649

27-
EXPECT_TRUE(success);
50+
pthread::this_thread::sleep_for(500); // just to let time to startup the thread.
51+
52+
EXPECT_FALSE(mutex.try_lock()); // return false, because the test thread has already locked the mutex
53+
EXPECT_NO_THROW(pthread::lock_guard<pthread::mutex> lock(mutex));
54+
EXPECT_TRUE(mutex.try_lock()); // the test thread has ended and the lock can be aquired again
55+
56+
mtr.join();
2857
}
2958

3059
TEST(concurrency, read_write_lock) {
31-
bool success = false ;
60+
bool success = false;
61+
62+
try {
63+
pthread::mutex mutex;
3264

33-
try {
65+
concurrency_test_runnable thread{&mutex};
66+
thread.start();
3467

35-
pthread::read_write_lock _rwlock;
68+
thread.set_something(1000);
69+
EXPECT_EQ(1000, thread.something());
3670

37-
{
38-
pthread::lock_guard<pthread::read_lock> lock(_rwlock);
71+
pthread::read_write_lock _rwlock;
3972

40-
// std::cout << "read locked" << std::endl;
41-
}
73+
{
74+
pthread::lock_guard<pthread::read_lock> lock(_rwlock);
4275

43-
{
44-
pthread::lock_guard<pthread::write_lock> lock(_rwlock);
45-
// std::cout << "write locked" << std::endl;
46-
}
76+
}
4777

48-
success = true;
78+
{
79+
pthread::lock_guard<pthread::write_lock> lock(_rwlock);
80+
}
4981

50-
}catch (std::exception &err ){
51-
std::cerr << __FILE__ << "(at:" << __LINE__ << ")" << err.what() << std::endl;
52-
}
82+
thread.join();
5383

54-
EXPECT_TRUE(success);
84+
success = true;
85+
86+
} catch (std::exception &err) {
87+
std::cerr << __FILE__ << "(at:" << __LINE__ << ")" << err.what() << std::endl;
88+
}
89+
90+
EXPECT_TRUE(success);
5591
}
5692

5793
TEST(concurrency, try_read_write_lock) {
58-
bool success = false ;
94+
bool success = false;
5995

6096
try {
6197

@@ -66,50 +102,54 @@ TEST(concurrency, try_read_write_lock) {
66102

67103
success = true;
68104

69-
}catch ( const std::exception &err ){
105+
} catch (const std::exception &err) {
70106
std::cerr << err.what() << std::endl << std::flush;
71107
}
72108

73109
EXPECT_TRUE(success);
74110
}
75111

76-
TEST(concurrency, condition_variable_wait_for){
112+
TEST(concurrency, condition_variable_wait_for) {
77113
pthread::condition_variable condition;
78-
pthread::mutex mutex;
79-
bool stop_waiting = true;
114+
pthread::mutex mutex;
115+
bool stop_waiting = true;
80116

81117
/* wait 1s for condition to be signaled. When returning from the wait_for method call, the mutex is locked.
82118
*
83119
* Therefore we expect, try_lock to throw an exception to signal that the mutex is already locked.
84120
*/
85-
EXPECT_EQ(pthread::cv_status::timedout, condition.wait_for(mutex, 1*1000));
86-
EXPECT_THROW(mutex.try_lock(), pthread::pthread_exception);
121+
EXPECT_EQ(pthread::cv_status::timedout, condition.wait_for(mutex, 1 * 1000));
122+
EXPECT_FALSE(mutex.try_lock());
87123
mutex.unlock(); // free to lock
88124

125+
EXPECT_NO_THROW(condition.notify_all());
126+
EXPECT_NO_THROW(condition.notify_one());
127+
89128
{
90129
pthread::lock_guard<pthread::mutex> lock{mutex};
91130
EXPECT_EQ(pthread::cv_status::timedout, condition.wait_for(lock, 1 * 1000));
92131
}
93132

94133
{
95134
pthread::lock_guard<pthread::mutex> lock{mutex};
96-
EXPECT_EQ(true, condition.wait_for(lock, 1 * 1000, [stop_waiting]{
97-
std::cout << "running lambda, stop_waiting : " << stop_waiting << std::endl ;
98-
return stop_waiting;
99-
}
100-
)
135+
EXPECT_EQ(true, condition.wait_for(lock, 1 * 1000, [stop_waiting] {
136+
std::cout << "running lambda, stop_waiting : " << stop_waiting << std::endl;
137+
return stop_waiting;
138+
}
139+
)
101140
);
102141
}
103142

104143

105144
{
106145
pthread::lock_guard<pthread::mutex> lock{mutex};
107-
EXPECT_EQ(false, condition.wait_for(lock, 1 * 1000, [stop_waiting]{
108-
std::cout << "running lambda, stop_waiting : " << stop_waiting << std::endl ;
109-
return ! stop_waiting;
110-
}
111-
)
146+
EXPECT_EQ(false,
147+
condition.wait_for(lock, 1 * 1000, [stop_waiting] {
148+
std::cout << "running lambda, stop_waiting : " << stop_waiting << std::endl;
149+
return !stop_waiting;
150+
})
112151
);
152+
113153
}
114154
}
115155

tests/exceptions_tests.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ TEST(exceptions, condition_variable_exception) {
4444

4545
try {
4646
throw pthread::condition_variable_exception();
47-
} catch (pthread::pthread_exception &ex) {
47+
} catch (pthread::condition_variable_exception &ex) {
4848
EXPECT_STREQ("conditional_variable_exception", ex.what());
4949
EXPECT_EQ(0, ex.error_number());
5050
}
@@ -82,6 +82,8 @@ TEST(exceptions, timeout_exception) {
8282
}
8383
}
8484

85+
// pthread::util exception -----------------------------------------
86+
8587
TEST(exceptions, util_queue_exception) {
8688
std::string expecting = "Condition variable exception test. ";
8789
expecting += strerror(-1);
@@ -95,15 +97,15 @@ TEST(exceptions, util_queue_exception) {
9597
TEST(exceptions, util_queue_full_exception) {
9698
try {
9799
throw pthread::util::queue_full();
98-
} catch (std::exception &ex) {
100+
} catch (pthread::util::queue_exception &ex) {
99101
EXPECT_STREQ("synchronized_queue full.", ex.what());
100102
}
101103
}
102104

103105
TEST(exceptions, util_queue_access_timeout_exception) {
104106
try {
105107
throw pthread::util::queue_timeout();
106-
} catch (std::exception &ex) {
108+
} catch (pthread::util::queue_exception &ex) {
107109
EXPECT_STREQ("synchronized_queue get/put timed out.", ex.what());
108110
}
109111
}

tests/thread_tests.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <string>
1212
#include <memory>
1313
#include <ctime>
14+
#include <chrono>
1415

1516
class test_runnable : public pthread::runnable {
1617
public:
@@ -92,7 +93,7 @@ TEST(thread, stack_size) {
9293
// This should work
9394
std::unique_ptr<test_runnable> tr{new test_runnable{"status test"}};
9495
pthread::thread t{*tr, initialized_stack_size};
95-
EXPECT_EQ(t.stact_size(), initialized_stack_size);
96+
EXPECT_EQ(t.stack_size(), initialized_stack_size);
9697
t.join();
9798

9899
// This should NOT work
@@ -129,6 +130,7 @@ TEST(thread, thread_constructor) {
129130
pthread::thread t2{*tr};
130131
EXPECT_EQ(t2.status(), pthread::thread_status::a_thread);
131132
t2.join();
133+
132134
} catch (std::exception &err) {
133135
std::cerr << "thread_constructor test failed. " << err.what() << std::endl;
134136
}
@@ -151,4 +153,23 @@ TEST(thread, move_operator) {
151153

152154
T2.join();
153155
EXPECT_NO_THROW(T2.join());
156+
157+
pthread::thread T3;
158+
T3 = std::move(T2);
159+
EXPECT_EQ(T3.status(), pthread::thread_status::not_a_thread);
160+
154161
}
162+
163+
TEST(thread, this_thread_sleep) {
164+
auto start = std::chrono::steady_clock::now();
165+
pthread::this_thread::sleep_for(500);
166+
pthread::this_thread::sleep_for(1500);
167+
pthread::this_thread::sleep_for(1000);
168+
pthread::this_thread::sleep_for(0);
169+
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(start - std::chrono::steady_clock::now()).count();
170+
EXPECT_GT(2.3, duration);
171+
}
172+
173+
TEST(thread, this_thread_get_id) {
174+
auto id = pthread::this_thread::get_id();
175+
}

0 commit comments

Comments
 (0)