forked from ThePhD/sol2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstd_thread.cpp
More file actions
157 lines (139 loc) · 4.01 KB
/
std_thread.cpp
File metadata and controls
157 lines (139 loc) · 4.01 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <variant>
#include <cstddef>
#include <iostream>
struct worker_data {
std::mutex until_ready_mutex;
std::condition_variable until_ready_condition;
bool is_ready = false;
bool is_processed = false;
sol::state worker_lua;
sol::bytecode payload;
std::variant<double, std::vector<double>> return_payload;
worker_data() {
worker_lua.open_libraries(sol::lib::base);
}
};
void worker_thread(worker_data& data) {
for (std::uint64_t loops = 0; true; ++loops) {
// Wait until main() sends data
std::unique_lock<std::mutex> data_lock(
data.until_ready_mutex);
data.until_ready_condition.wait(
data_lock, [&data] { return data.is_ready; });
if (data.payload.size() == 0) {
// signaling we are done
return;
}
// just for easier typing
sol::state& lua = data.worker_lua;
// we own the lock now, do the work
std::variant<double, std::vector<double>> result
= lua.safe_script(data.payload.as_string_view());
// store returning payload,
// clear current payload
data.return_payload = std::move(result);
data.payload.clear();
// Send result back to main
std::cout << "worker_thread data processing is "
"completed: signaling & unlocking\n";
data.is_processed = true;
data.is_ready = false;
data_lock.unlock();
data.until_ready_condition.notify_one();
}
}
int main() {
// main lua state
sol::state lua;
lua.open_libraries(sol::lib::base);
// set up functions, etc. etc.
lua.script("function f () return 4.5 end");
lua.script("function g () return { 1.1, 2.2, 3.3 } end");
// kick off worker
worker_data data;
std::thread worker(worker_thread, std::ref(data));
// main Lua state
bool done_working = false;
for (std::uint64_t loops = 0; !done_working; ++loops) {
// finished working? send nothing
// even loop? use f
// otherwise, use g
if (loops >= 3) {
data.payload.clear();
done_working = true;
}
else if ((loops % 2) == 0) {
sol::function target = lua["f"];
data.payload = target.dump();
}
else {
sol::function target = lua["g"];
data.payload = target.dump();
}
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(
data.until_ready_mutex);
data.is_ready = true;
std::cout
<< "function serialized: sending to worker "
"thread to execute on Lua state...\n";
}
data.until_ready_condition.notify_one();
if (done_working) {
break;
}
// wait for the worker
{
std::unique_lock<std::mutex>
lock_waiting_for_worker(
data.until_ready_mutex);
data.until_ready_condition.wait(
lock_waiting_for_worker,
[&data] { return data.is_processed; });
data.is_processed = false;
}
auto data_processor = [](auto& returned_data) {
using option_type
= std::remove_cv_t<std::remove_reference_t<
decltype(returned_data)>>;
if constexpr (std::is_same_v<option_type,
double>) {
std::cout << "received a double: "
<< returned_data << "\n";
}
else if constexpr (std::is_same_v<option_type,
std::vector<double>>) {
std::cout
<< "received a std::vector<double>: { ";
for (std::size_t i = 0;
i < returned_data.size();
++i) {
std::cout << returned_data[i];
if (i
!= static_cast<std::size_t>(
returned_data.size() - 1)) {
std::cout << ", ";
}
}
std::cout << " }\n";
}
else {
std::cerr << "OH MY GOD YOU FORGOT TO "
"HANDLE A TYPE OF DATA FROM A "
"WORKER ABORT ABORT ABORT\n";
std::abort();
}
};
std::visit(data_processor, data.return_payload);
}
// join and wait for workers to come back
worker.join();
// workers are back, exit program
return 0;
}