Skip to content

Commit 4dae4cc

Browse files
committed
Add semaphore
1 parent 57a1685 commit 4dae4cc

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

taskflow/executor/semaphore.hpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// - modified the thread monitor from TBB
2+
3+
#pragma once
4+
5+
#include "../predef/compiler.hpp"
6+
#include "../predef/os.hpp"
7+
8+
#if TF_COMP_MSVC || TF_COMP_MSVC_EMULATED
9+
#include <windows.h>
10+
#elif TF_COMP_GNUC || TF_COMP_GNUC_EMULATED
11+
#include <semaphore.h>
12+
#elif TF_OS_MACOS
13+
#include <mach/semaphore.h>
14+
#include <mach/task.h>
15+
#include <mach/mach_init.h>
16+
#include <mach/error.h>
17+
#else
18+
# error "Unsupported compiler"
19+
#endif
20+
21+
22+
#include <cassert>
23+
24+
namespace tf {
25+
26+
#if TF_COMP_MSVC || TF_COMP_MSVC_EMULATED
27+
struct BinarySemaphore {
28+
BinarySemaphore() {
29+
sem = CreateSemaphore(NULL, 0, 1, NULL);
30+
}
31+
32+
~BinarySemaphore() {
33+
CloseHandle(sem);
34+
}
35+
36+
void P() {
37+
WaitForSingleObject(sem, INFINITE);
38+
}
39+
40+
void V() {
41+
ReleaseSemaphore(sem, 1, NULL);
42+
}
43+
44+
private:
45+
HANDLE sem;
46+
BinarySemaphore(const BinarySemaphore& other) = delete;
47+
BinarySemaphore& operator=(const BinarySemaphore& other) = delete;
48+
};
49+
50+
#elif TF_COMP_GNUC || TF_COMP_GNUC_EMULATED
51+
struct BinarySemaphore {
52+
BinarySemaphore() {
53+
int ret = sem_init( &sem, 0, 0 );
54+
// Return 0 on success; -1 on error
55+
assert(ret == 0);
56+
}
57+
58+
~BinarySemaphore() {
59+
int ret = sem_destroy( &sem );
60+
// Return 0 on success; -1 on error
61+
assert(ret == 0);
62+
}
63+
64+
void P() {
65+
while( sem_wait( &sem )!=0 );
66+
}
67+
68+
void V() {
69+
sem_post( &sem );
70+
}
71+
72+
private:
73+
sem_t sem;
74+
BinarySemaphore(const BinarySemaphore& other) = delete;
75+
BinarySemaphore& operator=(const BinarySemaphore& other) = delete;
76+
};
77+
78+
#elif TF_OS_MACOS
79+
struct BinarySemaphore {
80+
81+
BinarySemaphore() : sem(0) {
82+
kern_return_t ret = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0);
83+
}
84+
85+
~BinarySemaphore() {
86+
kern_return_t ret = semaphore_destroy(mach_task_self(), sem);
87+
}
88+
89+
void P() {
90+
int ret;
91+
do {
92+
ret = semaphore_wait( sem );
93+
} while( ret==KERN_ABORTED );
94+
}
95+
96+
void V() {
97+
semaphore_signal( sem );
98+
}
99+
100+
private:
101+
semaphore_t sem;
102+
BinarySemaphore(const BinarySemaphore& other) = delete;
103+
BinarySemaphore& operator=(const BinarySemaphore& other) = delete;
104+
};
105+
106+
#else
107+
# error "Unsupported compiler"
108+
#endif
109+
110+
111+
} // end of namespace tf. ---------------------------------------------------
112+
113+

unittest/executor.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
#include <doctest.h>
4646
#include <taskflow/executor/executor.hpp>
4747

48+
#include <chrono>
49+
#include <taskflow/executor/semaphore.hpp>
50+
4851
// ============================================================================
4952
// WorkStealingQueue tests
5053
// ============================================================================
@@ -447,6 +450,8 @@ void test_executor() {
447450
}
448451
}
449452

453+
454+
450455
// ----------------------------------------------------------------------------
451456
// Testcase: SimpleExecutor
452457
// ----------------------------------------------------------------------------
@@ -482,3 +487,46 @@ TEST_CASE("EigenWorkStealingExecutor" * doctest::timeout(300)) {
482487
test_executor<tf::EigenWorkStealingExecutor<std::function<void()>>>();
483488
}
484489

490+
// ----------------------------------------------------------------------------
491+
// Testcase: BinarySemaphore
492+
// ----------------------------------------------------------------------------
493+
TEST_CASE("BinarySemaphore" * doctest::timeout(300)) {
494+
tf::BinarySemaphore sema;
495+
496+
size_t count {0};
497+
498+
std::thread t1([&](){
499+
using namespace std::chrono_literals;
500+
for(int i=0; i<100; i++) {
501+
std::this_thread::sleep_for(2ms);
502+
sema.P();
503+
++ count;
504+
}
505+
});
506+
507+
{
508+
using namespace std::chrono_literals;
509+
for(int i=0; i<100; i++) {
510+
sema.V();
511+
std::this_thread::sleep_for(10ms);
512+
REQUIRE(count == i+1);
513+
}
514+
}
515+
516+
t1.join();
517+
518+
519+
count = 0;
520+
std::thread t2([&](){
521+
using namespace std::chrono_literals;
522+
for(int i=0; i<10; i++) {
523+
std::this_thread::sleep_for(10ms);
524+
sema.V();
525+
count += 1;
526+
}
527+
});
528+
529+
t2.join();
530+
REQUIRE(count == 10);
531+
}
532+

0 commit comments

Comments
 (0)