这个奇怪的 clang 编译错误
This weird clang compile error
我有一个解决那些二维迷宫的程序,它对我来说工作得很好,但是我用 gprof
(和@jrfonseca 的花式 gprof2dot)对它进行了分析,在我看来它在某些操作上遇到了困难,因此决定进行一些并行化尝试。
基本上,在一个消耗 50%(cpu?)时间的函数中,我有两种并行化选择(单个队列的多个消费者 和 具有相似不相等参数的相同函数的并行调用) 但我想首先独立地做这两个来检查一个更好的初始假设,我并不总是做 C++ 代码,并通过搜索互联网上如何获得 std::thread
返回值 我在 std::future
上阅读了一个很好的答案和建议,然后我将其复制到我的代码中,所以请你知道这意味着什么......
bash-4.3$ sh build.sh
In file included from find_path.cpp:6:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/Xco
deDefault.xctoolchain/usr/bin/../include/c++/v1/future:371:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/thread:337:5: error:
attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_In...
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/thread:347:5:
in instantiation of function template specialization
'std::__1::__thread_execute<void
(*)(std::__1::priority_queue<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> &,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, std::__1::pair<int,
int> &, int, int, int, int, unsigned char *,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, int, int,
std::__1::promise<bool> &&),
std::__1::reference_wrapper<std::__1::priority_queue<std::__1::vector<std
::__1::pair<int,
int>, std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> >,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >,
std::__1::reference_wrapper<std::__1::pair<int, int> >, int, int, int,
int, const unsigned char *,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >, int, int,
std::__1::promise<bool> , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12>'
requested here
__thread_execute(*__p, _Index());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/thread:359:42: note:
in instantiation of function template specialization
'std::__1::__thread_proxy<std::__1::tuple<void
(*)(std::__1::priority_queue<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> &,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, std::__1::pair<int,
int> &, int, int, int, int, unsigned char *,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, int, int,
std::__1::promise<bool> &&),
std::__1::reference_wrapper<std::__1::priority_queue<std::__1::vector<std
::__1::pair<int,
int>, std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> >,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >,
std::__1::reference_wrapper<std::__1::pair<int, int> >, int, int, int,
int, const unsigned char *,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >, int, int,
std::__1::promise<bool> > >' requested here
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());
^
find_path.cpp:258:25: note: in instantiation of function template specializatio
n
'std::__1::thread::thread<void
(*)(std::__1::priority_queue<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> &,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, std::__1::pair<int,
int> &, int, int, int, int, unsigned char *,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, int, int,
std::__1::promise<bool> &&),
std::__1::reference_wrapper<std::__1::priority_queue<std::__1::vector<std
::__1::pair<int,
int>, std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> >,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >,
std::__1::reference_wrapper<std::__1::pair<int, int> >, int &, int &,
const int &, const int &, const unsigned char *&,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >, const int &, int,
std::__1::promise<bool> , void>' requested here
std::thread n(&move, std::ref(active_paths),
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/type_traits:1043:5: note:
'~__nat' has been explicitly marked deleted here
~__nat() = delete;
^
1 error generated.
bash-4.3$
...在这种情况下?
一些find_path.cpp:
1 // For 'assert(expression)'.
2 #include <cassert>
3 // For 'std::abs' (absolute value function, integers version)'.
4 #include <cstdlib>
5 // For 'std::promise' and 'std::future'.
6 #include <future> // <--
7 // For 'std::mutex'.
8 #include <mutex>
9 // For 'std::priority_queue'.
10 #include <queue>
11 // For 'std::move'.
12 #include <utility>
13 // For 'std::vector'.
14 #include <vector>
15 // For 'std::thread'.
16 #include <thread>
17 // For 'std::get', 'std::make_tuple' and 'std::tuple'.
18 #include <tuple>
还有一些:
242 // Do not add new paths unless deemed necessary.
243 bool add_north_move, add_west_move, add_south_move, add_east_move;
244 add_north_move = add_west_move = add_south_move = add_east_move =
245 0;
246
247 // Another helper.
248 std::vector < std::pair < int, int > > active_paths_top =
249 active_paths.top();
250 std::pair < int, int > active_paths_top_back =
251 active_paths_top.back();
252
253 // Directions clockwise (0: 'N', 1: 'E', 2: 'S', 3: 'W').
254 int direction = 0;
255
256 std::promise < bool > n_p;
257 auto n_f = n_p.get_future();
258 std::thread n(&move, std::ref(active_paths), // <--
259 std::ref(active_paths_top),
260 std::ref(active_paths_top_back), new_move_back_x, new_move_back_y,
261 nMapWidth, nMapHeight, pMap, std::ref(north_move), nOutBufferSize, direction++, std::move(n_p)
262 );
263 std::promise < bool > e_p;
264 auto e_f = e_p.get_future();
265 std::thread e(&move, std::ref(active_paths),
266 std::ref(active_paths_top),
267 std::ref(active_paths_top_back), new_move_back_x, new_move_back_y,
268 nMapWidth, nMapHeight, pMap, std::ref(east_move), nOutBufferSize, direction++, std::move(e_p)
269 );
void move(12)
中的内容:
108 void move(std::priority_queue <
109 std::vector < std::pair < int, int > >,
110 std::vector < std::vector < std::pair < int, int > > >,
111 NearerTarget
112 > & active_paths,
113 std::vector < std::pair < int, int > > & active_paths_top,
114 std::pair < int, int > & active_paths_top_back, int new_move_back_x, int new_move_back_y,
115 int map_width, int map_height, unsigned char * map, std::vector < std::pair < int, int > > & move,
116 int out_buffer_size, int direction,
117 std::promise < bool > && add_move) {
118 assert(-1 < direction && 4 > direction);
119 std::pair < int, int > new_coord;
120 switch (direction) {
121 case 0:
122 // Add move 'N'.
123 new_coord = std::make_pair(
124 active_paths_top_back.first,
125 active_paths_top_back.second + 1);
126 break;
127 case 1:
128 // Add move 'E'.
129 new_coord = std::make_pair(
130 active_paths_top_back.first + 1,
131 active_paths_top_back.second);
132 break;
133 case 2:
134 // Add move 'S'.
135 new_coord = std::make_pair(
136 active_paths_top_back.first,
137 active_paths_top_back.second - 1);
138 break;
139 case 3:
140 // Add move 'W'.
141 new_coord = std::make_pair(
142 active_paths_top_back.first - 1,
143 active_paths_top_back.second);
144 break;
145 }
146
147 // Push it to the queue of paths only if the movement
148 // makes sense.
149 new_move_back_x = new_coord.first;
150 new_move_back_y = new_coord.second;
151 if (new_move_back_x > -1 && new_move_back_x < map_width &&
152 new_move_back_y > -1 && new_move_back_y < map_height)
153 {
154 // Move is inside bounds.
155
156 // Check collision detection.
157 if (map[new_move_back_y * map_width + new_move_back_x])
158 {
159 // Check not visited.
160 if (! visited(
161 new_move_back_x,
162 new_move_back_y,
163 active_paths.top()))
164 {
165 move = active_paths_top;
166 move.reserve(out_buffer_size);
167 move.push_back(new_coord);
168 add_move.set_value(true);
169 }
170 }
171 }
172 }
它告诉我明确标记为已删除~__nat
,我什至不记得做过这样的事情。
我有点习惯 pthreads、Python 线程、Java 并行模型...不太精通不确定的选择、一般的异步、promises...我应该努力离开 std::future
使用?
错误消息与新的 C++ 功能有关,'deleting' 默认运算符使它们不可访问(以前,通常的技术是将它们设为私有)。
在您的情况下,这表明线程构造函数的参数存在问题。您的代码非常复杂,但您可能 运行 遇到这个问题:
我肯定会建议继续std:future。作为介绍,强烈推荐 Herb Sutter 关于新的 C++ 并发特性的以下演讲:https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Herb-Sutter-Concurrency-and-Parallelism
我有一个解决那些二维迷宫的程序,它对我来说工作得很好,但是我用 gprof
(和@jrfonseca 的花式 gprof2dot)对它进行了分析,在我看来它在某些操作上遇到了困难,因此决定进行一些并行化尝试。
基本上,在一个消耗 50%(cpu?)时间的函数中,我有两种并行化选择(单个队列的多个消费者 和 具有相似不相等参数的相同函数的并行调用) 但我想首先独立地做这两个来检查一个更好的初始假设,我并不总是做 C++ 代码,并通过搜索互联网上如何获得 std::thread
返回值 我在 std::future
上阅读了一个很好的答案和建议,然后我将其复制到我的代码中,所以请你知道这意味着什么......
bash-4.3$ sh build.sh
In file included from find_path.cpp:6:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/Xco
deDefault.xctoolchain/usr/bin/../include/c++/v1/future:371:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/thread:337:5: error:
attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_In...
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/thread:347:5:
in instantiation of function template specialization
'std::__1::__thread_execute<void
(*)(std::__1::priority_queue<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> &,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, std::__1::pair<int,
int> &, int, int, int, int, unsigned char *,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, int, int,
std::__1::promise<bool> &&),
std::__1::reference_wrapper<std::__1::priority_queue<std::__1::vector<std
::__1::pair<int,
int>, std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> >,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >,
std::__1::reference_wrapper<std::__1::pair<int, int> >, int, int, int,
int, const unsigned char *,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >, int, int,
std::__1::promise<bool> , 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12>'
requested here
__thread_execute(*__p, _Index());
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/thread:359:42: note:
in instantiation of function template specialization
'std::__1::__thread_proxy<std::__1::tuple<void
(*)(std::__1::priority_queue<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> &,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, std::__1::pair<int,
int> &, int, int, int, int, unsigned char *,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, int, int,
std::__1::promise<bool> &&),
std::__1::reference_wrapper<std::__1::priority_queue<std::__1::vector<std
::__1::pair<int,
int>, std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> >,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >,
std::__1::reference_wrapper<std::__1::pair<int, int> >, int, int, int,
int, const unsigned char *,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >, int, int,
std::__1::promise<bool> > >' requested here
int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());
^
find_path.cpp:258:25: note: in instantiation of function template specializatio
n
'std::__1::thread::thread<void
(*)(std::__1::priority_queue<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> &,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, std::__1::pair<int,
int> &, int, int, int, int, unsigned char *,
std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > &, int, int,
std::__1::promise<bool> &&),
std::__1::reference_wrapper<std::__1::priority_queue<std::__1::vector<std
::__1::pair<int,
int>, std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::vector<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > >,
std::__1::allocator<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > > >, NearerTarget> >,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >,
std::__1::reference_wrapper<std::__1::pair<int, int> >, int &, int &,
const int &, const int &, const unsigned char *&,
std::__1::reference_wrapper<std::__1::vector<std::__1::pair<int, int>,
std::__1::allocator<std::__1::pair<int, int> > > >, const int &, int,
std::__1::promise<bool> , void>' requested here
std::thread n(&move, std::ref(active_paths),
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/../include/c++/v1/type_traits:1043:5: note:
'~__nat' has been explicitly marked deleted here
~__nat() = delete;
^
1 error generated.
bash-4.3$
...在这种情况下?
一些find_path.cpp:
1 // For 'assert(expression)'.
2 #include <cassert>
3 // For 'std::abs' (absolute value function, integers version)'.
4 #include <cstdlib>
5 // For 'std::promise' and 'std::future'.
6 #include <future> // <--
7 // For 'std::mutex'.
8 #include <mutex>
9 // For 'std::priority_queue'.
10 #include <queue>
11 // For 'std::move'.
12 #include <utility>
13 // For 'std::vector'.
14 #include <vector>
15 // For 'std::thread'.
16 #include <thread>
17 // For 'std::get', 'std::make_tuple' and 'std::tuple'.
18 #include <tuple>
还有一些:
242 // Do not add new paths unless deemed necessary.
243 bool add_north_move, add_west_move, add_south_move, add_east_move;
244 add_north_move = add_west_move = add_south_move = add_east_move =
245 0;
246
247 // Another helper.
248 std::vector < std::pair < int, int > > active_paths_top =
249 active_paths.top();
250 std::pair < int, int > active_paths_top_back =
251 active_paths_top.back();
252
253 // Directions clockwise (0: 'N', 1: 'E', 2: 'S', 3: 'W').
254 int direction = 0;
255
256 std::promise < bool > n_p;
257 auto n_f = n_p.get_future();
258 std::thread n(&move, std::ref(active_paths), // <--
259 std::ref(active_paths_top),
260 std::ref(active_paths_top_back), new_move_back_x, new_move_back_y,
261 nMapWidth, nMapHeight, pMap, std::ref(north_move), nOutBufferSize, direction++, std::move(n_p)
262 );
263 std::promise < bool > e_p;
264 auto e_f = e_p.get_future();
265 std::thread e(&move, std::ref(active_paths),
266 std::ref(active_paths_top),
267 std::ref(active_paths_top_back), new_move_back_x, new_move_back_y,
268 nMapWidth, nMapHeight, pMap, std::ref(east_move), nOutBufferSize, direction++, std::move(e_p)
269 );
void move(12)
中的内容:
108 void move(std::priority_queue <
109 std::vector < std::pair < int, int > >,
110 std::vector < std::vector < std::pair < int, int > > >,
111 NearerTarget
112 > & active_paths,
113 std::vector < std::pair < int, int > > & active_paths_top,
114 std::pair < int, int > & active_paths_top_back, int new_move_back_x, int new_move_back_y,
115 int map_width, int map_height, unsigned char * map, std::vector < std::pair < int, int > > & move,
116 int out_buffer_size, int direction,
117 std::promise < bool > && add_move) {
118 assert(-1 < direction && 4 > direction);
119 std::pair < int, int > new_coord;
120 switch (direction) {
121 case 0:
122 // Add move 'N'.
123 new_coord = std::make_pair(
124 active_paths_top_back.first,
125 active_paths_top_back.second + 1);
126 break;
127 case 1:
128 // Add move 'E'.
129 new_coord = std::make_pair(
130 active_paths_top_back.first + 1,
131 active_paths_top_back.second);
132 break;
133 case 2:
134 // Add move 'S'.
135 new_coord = std::make_pair(
136 active_paths_top_back.first,
137 active_paths_top_back.second - 1);
138 break;
139 case 3:
140 // Add move 'W'.
141 new_coord = std::make_pair(
142 active_paths_top_back.first - 1,
143 active_paths_top_back.second);
144 break;
145 }
146
147 // Push it to the queue of paths only if the movement
148 // makes sense.
149 new_move_back_x = new_coord.first;
150 new_move_back_y = new_coord.second;
151 if (new_move_back_x > -1 && new_move_back_x < map_width &&
152 new_move_back_y > -1 && new_move_back_y < map_height)
153 {
154 // Move is inside bounds.
155
156 // Check collision detection.
157 if (map[new_move_back_y * map_width + new_move_back_x])
158 {
159 // Check not visited.
160 if (! visited(
161 new_move_back_x,
162 new_move_back_y,
163 active_paths.top()))
164 {
165 move = active_paths_top;
166 move.reserve(out_buffer_size);
167 move.push_back(new_coord);
168 add_move.set_value(true);
169 }
170 }
171 }
172 }
它告诉我明确标记为已删除~__nat
,我什至不记得做过这样的事情。
我有点习惯 pthreads、Python 线程、Java 并行模型...不太精通不确定的选择、一般的异步、promises...我应该努力离开 std::future
使用?
错误消息与新的 C++ 功能有关,'deleting' 默认运算符使它们不可访问(以前,通常的技术是将它们设为私有)。
在您的情况下,这表明线程构造函数的参数存在问题。您的代码非常复杂,但您可能 运行 遇到这个问题:
我肯定会建议继续std:future。作为介绍,强烈推荐 Herb Sutter 关于新的 C++ 并发特性的以下演讲:https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Herb-Sutter-Concurrency-and-Parallelism