Skip to content

Commit b6a8724

Browse files
author
Kolkir
committed
Process lock implementation Kolkir#9
1 parent 1651180 commit b6a8724

4 files changed

Lines changed: 111 additions & 100 deletions

File tree

‎include/cpptask/event.h‎

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#ifndef _EVENT_H_
2929
#define _EVENT_H_
3030

31+
#include "taskmanager.h"
32+
3133
#include <condition_variable>
3234

3335
namespace cpptask
@@ -54,26 +56,23 @@ class event
5456
cv.notify_all();
5557
}
5658

57-
void reset()
58-
{
59-
std::unique_lock<std::mutex> lock(guard);
60-
signaled = false;
61-
}
62-
6359
void wait()
6460
{
6561
std::unique_lock<std::mutex> lock(guard);
66-
if (signaled)
67-
{
68-
return;
69-
}
7062
cv.wait(lock, [&] {return signaled; });
63+
signaled = false;
7164
}
7265

7366
bool check()
7467
{
7568
std::unique_lock<std::mutex> lock(guard);
76-
return signaled;
69+
if (cv.wait_for(lock, std::chrono::milliseconds(0), [&] {return signaled; }))
70+
{
71+
signaled = false;
72+
cv.notify_all();
73+
return true;
74+
}
75+
return false;
7776
}
7877

7978
private:
@@ -103,11 +102,6 @@ class lockable_event
103102
TaskManager::GetCurrent().GetEventManager().notify(EventId::CustomEvent);
104103
}
105104

106-
void reset()
107-
{
108-
evt.reset();
109-
}
110-
111105
void lock()
112106
{
113107
evt.wait();

‎include/cpptask/semaphor.h‎

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#ifndef _SEMAPHORE_H_
2929
#define _SEMAPHORE_H_
3030

31+
#include "taskmanager.h"
32+
3133
#include <condition_variable>
3234

3335
namespace cpptask
@@ -47,7 +49,8 @@ namespace cpptask
4749
void unlock()
4850
{
4951
std::lock_guard<std::mutex> lock{ guard };
50-
if (maxCount > 0 && count < maxCount)
52+
if ((maxCount > 0 && count < maxCount) ||
53+
maxCount <= 0)
5154
{
5255
++count;
5356
cv.notify_one();
@@ -78,5 +81,41 @@ namespace cpptask
7881
std::condition_variable cv;
7982
std::mutex guard;
8083
};
84+
85+
//use this class only if you have corresponding process_lock object
86+
class lockable_semaphore
87+
{
88+
public:
89+
typedef EventManager EventManagerType;
90+
91+
explicit lockable_semaphore(int n = 0, int max = -1) noexcept
92+
: sem(n, max)
93+
{}
94+
95+
~lockable_semaphore()
96+
{}
97+
98+
lockable_semaphore(const lockable_semaphore&) = delete;
99+
const lockable_semaphore& operator=(const lockable_semaphore&) = delete;
100+
101+
void lock()
102+
{
103+
sem.lock();
104+
}
105+
106+
void unlock()
107+
{
108+
sem.unlock();
109+
TaskManager::GetCurrent().GetEventManager().notify(EventId::CustomEvent);
110+
}
111+
112+
bool try_lock()
113+
{
114+
return sem.try_lock();
115+
}
116+
117+
private:
118+
semaphore sem;
119+
};
81120
}
82121
#endif

‎tests/process_lock_test.cpp‎

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,28 @@ namespace
1111
std::mutex guard;
1212
cpptask::mutex guard2;
1313
cpptask::lockable_event event1;
14+
cpptask::lockable_semaphore sem1(1,2);
1415

1516
void processFuncLock()
1617
{
1718
std::lock_guard<std::mutex> lock(guard);
1819
std::this_thread::sleep_for(std::chrono::milliseconds(10));
1920
}
20-
void processFuncLock2()
21+
void processFuncLockMutex()
2122
{
2223
cpptask::process_lock<cpptask::mutex> lock(guard2); //allow use thread for calculations
2324
std::this_thread::sleep_for(std::chrono::milliseconds(10));
2425
}
25-
void processFuncLock3()
26+
void processFuncLockEvent()
2627
{
2728
cpptask::process_lock<cpptask::lockable_event> lock(event1); //allow use thread for calculations
2829
std::this_thread::sleep_for(std::chrono::milliseconds(10));
2930
}
31+
void processFuncLockSem()
32+
{
33+
cpptask::process_lock<cpptask::lockable_semaphore> lock(sem1); //allow use thread for calculations
34+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
35+
}
3036
}
3137

3238
TEST_F(CppTaskTest, ProcessLock_Serial)
@@ -50,7 +56,7 @@ TEST_F(CppTaskTest, ProcessLock_Parallel)
5056
cpptask::TaskThreadPool threadPool(1);
5157

5258
std::unique_lock<cpptask::mutex> lock(guard2);
53-
auto f1 = cpptask::async(std::launch::async, processFuncLock2);
59+
auto f1 = cpptask::async(std::launch::async, processFuncLockMutex);
5460
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // additional thread blocked, he stole task
5561
ASSERT_NO_THROW(cpptask::for_each(testArray2.begin(), testArray2.end(), CppTaskTestData::DoubleSqrt(), 4)); //generate more tasks
5662
lock.unlock(); //unlock after second tasks done
@@ -64,7 +70,7 @@ TEST_F(CppTaskTest, ProcessLock_ParallelEvent)
6470
{
6571
cpptask::TaskThreadPool threadPool(1);
6672

67-
auto f1 = cpptask::async(std::launch::async, processFuncLock3);
73+
auto f1 = cpptask::async(std::launch::async, processFuncLockEvent);
6874
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // additional thread blocked, he stole task
6975
ASSERT_NO_THROW(cpptask::for_each(testArray2.begin(), testArray2.end(), CppTaskTestData::DoubleSqrt(), 4)); //generate more tasks
7076
event1.notify(); //unlock after second tasks done
@@ -73,3 +79,18 @@ TEST_F(CppTaskTest, ProcessLock_ParallelEvent)
7379

7480
ASSERT_EQ(CppTaskTestData::instance().getResultArray(), testArray2);
7581
}
82+
83+
TEST_F(CppTaskTest, ProcessLock_ParallelSemaphore)
84+
{
85+
cpptask::TaskThreadPool threadPool(1);
86+
87+
std::unique_lock<cpptask::lockable_semaphore> lock(sem1);
88+
auto f1 = cpptask::async(std::launch::async, processFuncLockSem);
89+
std::this_thread::sleep_for(std::chrono::milliseconds(10)); // additional thread blocked, he stole task
90+
ASSERT_NO_THROW(cpptask::for_each(testArray2.begin(), testArray2.end(), CppTaskTestData::DoubleSqrt(), 4)); //generate more tasks
91+
lock.unlock(); //unlock after second tasks done
92+
93+
f1.wait();
94+
95+
ASSERT_EQ(CppTaskTestData::instance().getResultArray(), testArray2);
96+
}

‎tests/sync_test.cpp‎

Lines changed: 36 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,66 @@
11
#include <gtest/gtest.h>
2-
/*
3-
#include <cpptask/event.h>
4-
#include <cpptask/semaphor.h>
5-
#include <cpptask/waitoneof.h>
2+
3+
#include <cpptask/cpptask.h>
64

75
#include <future>
86

97
TEST(SyncTest, Event)
108
{
11-
cpptask::event m;
9+
int count = 0;
10+
cpptask::event e1;
11+
cpptask::event e2;
1212
{
13-
m.notify();
14-
auto f = std::async([&]()
13+
auto f = std::async(std::launch::async, [&]()
1514
{
16-
ASSERT_TRUE(m.check());
15+
while (count != 5)
16+
{
17+
e1.wait();
18+
++count;
19+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
20+
e2.notify();
21+
}
1722
});
23+
24+
for (int i = 0; i < 5; ++i)
25+
{
26+
e1.notify();
27+
e2.wait();
28+
}
1829
f.wait();
1930
}
20-
m.notify();
21-
m.notify();
22-
}
23-
24-
TEST(SyncTest, EventMultipleImmediateUnlock)
25-
{
26-
cpptask::event e1;
27-
cpptask::event e2;
28-
29-
cpptask::wait_one_of waits{&e1, &e2};
30-
31-
e2.notify();
32-
auto f = std::async([&]()
33-
{
34-
ASSERT_EQ(1, waits.wait());
35-
});
36-
f.wait();
37-
38-
e1.notify();
39-
e2.notify();
40-
}
41-
42-
TEST(SyncTest, EventMultipleWaitUnlock)
43-
{
44-
cpptask::event e1;
45-
cpptask::event e2;
46-
47-
cpptask::wait_one_of waits {&e1, &e2 };
48-
49-
auto f = std::async([&]()
50-
{
51-
int res = waits.wait();
52-
ASSERT_EQ(0, res);
53-
});
54-
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
55-
e1.notify();
56-
57-
f.wait();
31+
ASSERT_EQ(5, count);
5832
}
5933

60-
6134
TEST(SyncTest, Semaphore)
6235
{
63-
cpptask::semaphore s(2);
36+
cpptask::semaphore s(2,2);
6437
{
65-
66-
auto f1 = std::async([&]()
38+
auto f1 = std::async(std::launch::async,[&]()
6739
{
68-
ASSERT_TRUE(s.check());
40+
s.lock();
41+
std::cout << "f1\n";
42+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
43+
s.unlock();
6944
});
7045

71-
auto f2 = std::async([&]()
46+
auto f2 = std::async(std::launch::async,[&]()
7247
{
73-
ASSERT_TRUE(s.check());
48+
s.lock();
49+
std::cout << "f2\n";
50+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
51+
s.unlock();
7452
});
7553

76-
s.notify();
77-
auto f3 = std::async([&]()
54+
auto f3 = std::async(std::launch::async,[&]()
7855
{
79-
ASSERT_TRUE(s.check());
56+
s.lock();
57+
std::cout << "f3\n";
58+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
59+
s.unlock();
8060
});
8161

8262
f1.wait();
8363
f2.wait();
8464
f3.wait();
8565
}
8666
}
87-
88-
TEST(SyncTest, SemaphoreMultipleWaitUnlock)
89-
{
90-
cpptask::event e;
91-
cpptask::semaphore s;
92-
93-
cpptask::wait_one_of waits{&e,&s};
94-
95-
auto f = std::async([&]()
96-
{
97-
int res = waits.wait();
98-
ASSERT_EQ(1, res);
99-
});
100-
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
101-
s.notify();
102-
s.notify();
103-
s.notify();
104-
105-
f.wait();
106-
107-
e.notify();
108-
}
109-
*/

0 commit comments

Comments
 (0)