Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
a6cb56a0
Commit
a6cb56a0
authored
Jan 20, 2015
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Port examples to new atom constant syntax
parent
18bcf49c
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
264 additions
and
257 deletions
+264
-257
examples/aout.cpp
examples/aout.cpp
+8
-7
examples/brokers/simple_broker.cpp
examples/brokers/simple_broker.cpp
+13
-10
examples/brokers/simple_http_broker.cpp
examples/brokers/simple_http_broker.cpp
+5
-3
examples/curl/curl_fuse.cpp
examples/curl/curl_fuse.cpp
+53
-62
examples/message_passing/calculator.cpp
examples/message_passing/calculator.cpp
+32
-35
examples/message_passing/dancing_kirby.cpp
examples/message_passing/dancing_kirby.cpp
+11
-14
examples/message_passing/dining_philosophers.cpp
examples/message_passing/dining_philosophers.cpp
+105
-90
examples/remote_actors/distributed_calculator.cpp
examples/remote_actors/distributed_calculator.cpp
+29
-30
examples/remote_actors/group_chat.cpp
examples/remote_actors/group_chat.cpp
+8
-6
No files found.
examples/aout.cpp
View file @
a6cb56a0
/******************************************************************************\
* This example illustrates how to use aout. *
\
******************************************************************************/
\******************************************************************************/
#include <random>
#include <chrono>
...
...
@@ -20,16 +20,17 @@ int main() {
std
::
random_device
rd
;
std
::
default_random_engine
re
(
rd
());
std
::
chrono
::
milliseconds
tout
{
re
()
%
10
};
self
->
delayed_send
(
self
,
tout
,
atom
(
"done"
));
self
->
receive
(
others
()
>>
[
i
,
self
]
{
aout
(
self
)
<<
"Actor nr. "
<<
i
<<
" says goodbye!"
<<
endl
;
});
self
->
delayed_send
(
self
,
tout
,
42
);
self
->
receive
(
[
i
,
self
](
int
)
{
aout
(
self
)
<<
"Actor nr. "
<<
i
<<
" says goodbye!"
<<
endl
;
}
);
});
}
// wait until all other actors we've spawned are done
await_all_actors_done
();
// done
shutdown
();
return
0
;
}
examples/brokers/simple_broker.cpp
View file @
a6cb56a0
...
...
@@ -29,6 +29,10 @@ using namespace std;
using
namespace
caf
;
using
namespace
caf
::
io
;
using
ping_atom
=
atom_constant
<
atom
(
"ping"
)
>
;
using
pong_atom
=
atom_constant
<
atom
(
"pong"
)
>
;
using
kickoff_atom
=
atom_constant
<
atom
(
"kickoff"
)
>
;
// utility function to print an exit message with custom name
void
print_on_exit
(
const
actor
&
ptr
,
const
std
::
string
&
name
)
{
ptr
->
attach_functor
([
=
](
std
::
uint32_t
reason
)
{
...
...
@@ -39,12 +43,12 @@ void print_on_exit(const actor& ptr, const std::string& name) {
behavior
ping
(
event_based_actor
*
self
,
size_t
num_pings
)
{
auto
count
=
make_shared
<
size_t
>
(
0
);
return
{
on
(
atom
(
"kickoff"
),
arg_match
)
>>
[
=
](
const
actor
&
pong
)
{
self
->
send
(
pong
,
atom
(
"ping"
)
,
int32_t
(
1
));
[
=
](
kickoff_atom
,
const
actor
&
pong
)
{
self
->
send
(
pong
,
ping_atom
::
value
,
int32_t
(
1
));
self
->
become
(
on
(
atom
(
"pong"
),
arg_match
)
>>
[
=
](
int32_t
value
)
->
message
{
[
=
](
pong_atom
,
int32_t
value
)
->
message
{
if
(
++*
count
>=
num_pings
)
self
->
quit
();
return
make_message
(
atom
(
"ping"
)
,
value
+
1
);
return
make_message
(
ping_atom
::
value
,
value
+
1
);
}
);
}
...
...
@@ -53,8 +57,8 @@ behavior ping(event_based_actor* self, size_t num_pings) {
behavior
pong
()
{
return
{
on
(
atom
(
"ping"
),
arg_match
)
>>
[](
int32_t
value
)
{
return
make_message
(
atom
(
"pong"
)
,
value
);
[](
ping_atom
,
int32_t
value
)
{
return
make_message
(
pong_atom
::
value
,
value
);
}
};
}
...
...
@@ -113,9 +117,8 @@ behavior broker_impl(broker* self, connection_handle hdl, const actor& buddy) {
}
},
[
=
](
atom_value
av
,
int32_t
i
)
{
assert
(
av
==
atom
(
"ping"
)
||
av
==
atom
(
"pong"
));
aout
(
self
)
<<
"send {"
<<
to_string
(
av
)
<<
", "
<<
i
<<
"}"
<<
endl
;
assert
(
av
==
ping_atom
::
value
||
av
==
pong_atom
::
value
);
aout
(
self
)
<<
"send {"
<<
to_string
(
av
)
<<
", "
<<
i
<<
"}"
<<
endl
;
// cast atom to its underlying type, i.e., uint64_t
write_int
(
self
,
hdl
,
static_cast
<
uint64_t
>
(
av
));
write_int
(
self
,
hdl
,
i
);
...
...
@@ -185,7 +188,7 @@ int main(int argc, char** argv) {
auto
io_actor
=
spawn_io_client
(
broker_impl
,
host
,
port
,
ping_actor
);
print_on_exit
(
io_actor
,
"protobuf_io"
);
print_on_exit
(
ping_actor
,
"ping"
);
send_as
(
io_actor
,
ping_actor
,
atom
(
"kickoff"
)
,
io_actor
);
send_as
(
io_actor
,
ping_actor
,
kickoff_atom
::
value
,
io_actor
);
},
others
()
>>
[]
{
cerr
<<
"use with eihter '-s PORT' as server or '-c HOST PORT' as client"
...
...
examples/brokers/simple_http_broker.cpp
View file @
a6cb56a0
...
...
@@ -11,6 +11,8 @@ using std::endl;
using
namespace
caf
;
using
namespace
caf
::
io
;
using
tick_atom
=
atom_constant
<
atom
(
"tick"
)
>
;
const
char
http_ok
[]
=
R"__(HTTP/1.1 200 OK
Content-Type: text/plain
Connection: keep-alive
...
...
@@ -44,7 +46,7 @@ behavior connection_worker(broker* self, connection_handle hdl) {
behavior
server
(
broker
*
self
)
{
auto
counter
=
std
::
make_shared
<
int
>
(
0
);
self
->
delayed_send
(
self
,
std
::
chrono
::
seconds
(
1
),
atom
(
"tick"
)
);
self
->
delayed_send
(
self
,
std
::
chrono
::
seconds
(
1
),
tick_atom
::
value
);
return
{
[
=
](
const
new_connection_msg
&
ncm
)
{
auto
worker
=
self
->
fork
(
connection_worker
,
ncm
.
handle
);
...
...
@@ -54,10 +56,10 @@ behavior server(broker* self) {
[
=
](
const
down_msg
&
)
{
++*
counter
;
},
on
(
atom
(
"tick"
))
>>
[
=
]
{
[
=
](
tick_atom
)
{
aout
(
self
)
<<
"Finished "
<<
*
counter
<<
" requests per second."
<<
endl
;
*
counter
=
0
;
self
->
delayed_send
(
self
,
std
::
chrono
::
seconds
(
1
),
atom
(
"tick"
)
);
self
->
delayed_send
(
self
,
std
::
chrono
::
seconds
(
1
),
tick_atom
::
value
);
},
others
()
>>
[
=
]
{
aout
(
self
)
<<
"unexpected: "
<<
to_string
(
self
->
last_dequeued
())
<<
endl
;
...
...
examples/curl/curl_fuse.cpp
View file @
a6cb56a0
...
...
@@ -7,25 +7,25 @@
* *
* Schematic view: *
* *
* client
| client_job | curl_master | curl_worker
*
*
/--------------|*|-------------\ /-------------|*|
*
*
/---------------|*|--------------\ /
*
*
/----------------|*|---------------\ /
*
* client
| client_job | curl_master | curl_worker
*
*
/--------------|*|-------------\ /-------------|*|
*
*
/---------------|*|--------------\ /
*
*
/----------------|*|---------------\ /
*
* |*| ----------------|*|----------------|*|----------------|*| *
*
\________________|*|_______________/ \
*
*
\_______________|*|______________/ \
*
*
\______________|*|_____________/ \-------------|*|
*
*
\________________|*|_______________/ \
*
*
\_______________|*|______________/ \
*
*
\______________|*|_____________/ \-------------|*|
*
* *
* *
* Communication pattern: *
* *
* client_job
curl_master curl_worker
*
* |
| |
*
* | ----(read)-----> |
|
*
* |
| --(forward)----> |
*
* |
|---\
*
* |
| |
*
* |
|<--/
*
* client_job
curl_master curl_worker
*
* |
| |
*
* | ----(read)-----> |
|
*
* |
| --(forward)----> |
*
* |
|---\
*
* |
| |
*
* |
|<--/
*
* | <-------------(reply)-------------- | *
* X *
\ ******************************************************************************/
...
...
@@ -49,15 +49,21 @@
// disable some clang warnings here caused by CURL
#ifdef __clang__
#
pragma clang diagnostic ignored "-Wshorten-64-to-32"
#
pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#
pragma clang diagnostic ignored "-Wunused-const-variable"
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
# pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
# pragma clang diagnostic ignored "-Wunused-const-variable"
#endif // __clang__
using
namespace
caf
;
using
buffer_type
=
std
::
vector
<
char
>
;
using
read_atom
=
atom_constant
<
atom
(
"read"
)
>
;
using
fail_atom
=
atom_constant
<
atom
(
"fail"
)
>
;
using
next_atom
=
atom_constant
<
atom
(
"next"
)
>
;
using
reply_atom
=
atom_constant
<
atom
(
"reply"
)
>
;
using
finished_atom
=
atom_constant
<
atom
(
"finished"
)
>
;
namespace
color
{
// UNIX terminal color codes
...
...
@@ -137,24 +143,19 @@ class client_job : public base_actor {
protected:
behavior
make_behavior
()
override
{
print
()
<<
"init"
<<
color
::
reset_endl
;
send
(
m_parent
,
atom
(
"read"
),
"http://www.example.com/index.html"
,
static_cast
<
uint64_t
>
(
0
),
static_cast
<
uint64_t
>
(
4095
));
return
(
on
(
atom
(
"reply"
),
arg_match
)
>>
[
=
](
const
buffer_type
&
buf
)
{
print
()
<<
"successfully received "
<<
buf
.
size
()
<<
" bytes"
<<
color
::
reset_endl
;
send
(
m_parent
,
read_atom
::
value
,
"http://www.example.com/index.html"
,
uint64_t
{
0
},
uint64_t
{
4095
});
return
{
[
=
](
reply_atom
,
const
buffer_type
&
buf
)
{
print
()
<<
"successfully received "
<<
buf
.
size
()
<<
" bytes"
<<
color
::
reset_endl
;
quit
();
},
on
(
atom
(
"fail"
))
>>
[
=
]
{
[
=
](
fail_atom
)
{
print
()
<<
"failure"
<<
color
::
reset_endl
;
quit
();
}
)
;
}
;
}
};
...
...
@@ -182,9 +183,9 @@ class client : public base_actor {
link_to
(
m_parent
);
print
()
<<
"init"
<<
color
::
reset_endl
;
// start 'loop'
send
(
this
,
atom
(
"next"
)
);
send
(
this
,
next_atom
::
value
);
return
(
on
(
atom
(
"next"
))
>>
[
=
]
{
[
=
](
next_atom
)
{
print
()
<<
"spawn new client_job (nr. "
<<
++
m_count
<<
")"
...
...
@@ -194,7 +195,7 @@ class client : public base_actor {
spawn
<
client_job
,
detached
+
linked
>
(
m_parent
);
// compute random delay until next job is launched
auto
delay
=
m_dist
(
m_re
);
delayed_send
(
this
,
milliseconds
(
delay
),
atom
(
"next"
)
);
delayed_send
(
this
,
milliseconds
(
delay
),
next_atom
::
value
);
}
);
}
...
...
@@ -227,9 +228,8 @@ class curl_worker : public base_actor {
curl_easy_setopt
(
m_curl
,
CURLOPT_WRITEFUNCTION
,
&
curl_worker
::
cb
);
curl_easy_setopt
(
m_curl
,
CURLOPT_NOSIGNAL
,
1
);
return
(
on
(
atom
(
"read"
),
arg_match
)
>>
[
=
](
const
std
::
string
&
fname
,
uint64_t
offset
,
uint64_t
range
)
->
message
{
[
=
](
read_atom
,
const
std
::
string
&
fname
,
uint64_t
offset
,
uint64_t
range
)
->
message
{
print
()
<<
"read"
<<
color
::
reset_endl
;
for
(;;)
{
m_buf
.
clear
();
...
...
@@ -266,8 +266,8 @@ class curl_worker : public base_actor {
<<
hc
<<
color
::
reset_endl
;
// tell parent that this worker is done
send
(
m_parent
,
atom
(
"finished"
)
);
return
make_message
(
atom
(
"reply"
)
,
m_buf
);
send
(
m_parent
,
finished_atom
::
value
);
return
make_message
(
reply_atom
::
value
,
m_buf
);
case
404
:
// file does not exist
print
()
<<
"http error: download failed with "
<<
"'HTTP RETURN CODE': 404 (file does "
...
...
@@ -305,7 +305,6 @@ curl_worker::~curl_worker() {
// avoid weak-vtables warning
}
// manages {num_curl_workers} workers with a round-robin protocol
class
curl_master
:
public
base_actor
{
public:
...
...
@@ -324,45 +323,37 @@ class curl_master : public base_actor {
}
auto
worker_finished
=
[
=
]
{
auto
sender
=
last_sender
();
auto
i
=
std
::
find
(
m_busy_worker
.
begin
(),
m_busy_worker
.
end
(),
sender
);
auto
i
=
std
::
find
(
m_busy_worker
.
begin
(),
m_busy_worker
.
end
(),
sender
);
m_idle_worker
.
push_back
(
*
i
);
m_busy_worker
.
erase
(
i
);
print
()
<<
"worker is done"
<<
color
::
reset_endl
;
};
print
()
<<
"spawned "
<<
m_idle_worker
.
size
()
<<
" worker"
<<
color
::
reset_endl
;
return
(
on
(
atom
(
"read"
),
arg_match
)
>>
[
=
](
const
std
::
string
&
,
uint64_t
,
uint64_t
)
{
print
()
<<
"spawned "
<<
m_idle_worker
.
size
()
<<
" worker(s)"
<<
color
::
reset_endl
;
return
{
[
=
](
read_atom
,
const
std
::
string
&
,
uint64_t
,
uint64_t
)
{
print
()
<<
"received {'read'}"
<<
color
::
reset_endl
;
// forward job to
first
idle worker
actor
worker
=
m_idle_worker
.
front
();
m_idle_worker
.
erase
(
m_idle_worker
.
begin
()
);
// forward job to
an
idle worker
actor
worker
=
m_idle_worker
.
back
();
m_idle_worker
.
pop_back
(
);
m_busy_worker
.
push_back
(
worker
);
forward_to
(
worker
);
print
()
<<
m_busy_worker
.
size
()
<<
" active jobs"
<<
color
::
reset_endl
;
print
()
<<
m_busy_worker
.
size
()
<<
" active jobs"
<<
color
::
reset_endl
;
if
(
m_idle_worker
.
empty
())
{
// wait until at least one worker finished its job
become
(
keep_behavior
,
on
(
atom
(
"finished"
))
>>
[
=
]
{
[
=
](
finished_atom
)
{
worker_finished
();
unbecome
();
}
);
}
},
on
(
atom
(
"finished"
))
>>
[
=
]
{
[
=
](
finished_atom
)
{
worker_finished
();
}
)
;
}
;
}
private:
...
...
@@ -409,9 +400,9 @@ int main() {
act
.
sa_handler
=
[](
int
)
{
abort
();
};
set_sighandler
();
aout
(
self
)
<<
color
::
cyan
<<
"await CURL; this may take a while "
"(press CTRL+C again to abort)"
<<
color
::
reset_endl
;
<<
"await CURL; this may take a while "
"(press CTRL+C again to abort)"
<<
color
::
reset_endl
;
self
->
await_all_other_actors_done
();
}
// shutdown libcaf
...
...
examples/message_passing/calculator.cpp
View file @
a6cb56a0
...
...
@@ -13,42 +13,37 @@ using std::cout;
using
std
::
endl
;
using
namespace
caf
;
using
plus_atom
=
atom_constant
<
atom
(
"plus"
)
>
;
using
minus_atom
=
atom_constant
<
atom
(
"minus"
)
>
;
// implementation using the blocking API
void
blocking_math_fun
(
blocking_actor
*
self
)
{
bool
done
=
false
;
self
->
do_receive
(
// "arg_match" matches the parameter types of given lambda expression
// thus, it's equal to
// - on<atom("plus"), int, int>()
// - on(atom("plus"), val<int>, val<int>)
on
(
atom
(
"plus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
{
return
std
::
make_tuple
(
atom
(
"result"
),
a
+
b
);
void
blocking_calculator
(
blocking_actor
*
self
)
{
self
->
receive_loop
(
[](
plus_atom
,
int
a
,
int
b
)
{
return
a
+
b
;
},
on
(
atom
(
"minus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
{
return
std
::
make_tuple
(
atom
(
"result"
),
a
-
b
)
;
[](
minus_atom
,
int
a
,
int
b
)
{
return
a
-
b
;
},
on
(
atom
(
"quit"
))
>>
[
&
]()
{
// note: this actor uses the blocking API, hence self->quit()
// would force stack unwinding by throwing an exception
done
=
true
;
others
()
>>
[
=
]
{
cout
<<
"unexpected: "
<<
to_string
(
self
->
last_dequeued
())
<<
endl
;
}
)
.
until
(
done
)
;
);
}
void
calculator
(
event_based_actor
*
self
)
{
// execute this behavior until actor terminates
self
->
become
(
on
(
atom
(
"plus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
{
return
std
::
make_tuple
(
atom
(
"result"
),
a
+
b
)
;
// execute this behavior until actor terminates
behavior
calculator
(
event_based_actor
*
self
)
{
return
behavior
{
[](
plus_atom
,
int
a
,
int
b
)
{
return
a
+
b
;
},
on
(
atom
(
"minus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
{
return
std
::
make_tuple
(
atom
(
"result"
),
a
-
b
)
;
[](
minus_atom
,
int
a
,
int
b
)
{
return
a
-
b
;
},
on
(
atom
(
"quit"
))
>>
[
=
]
{
// terminate actor with normal exit reason
self
->
quit
();
others
()
>>
[
=
]
{
cout
<<
"unexpected: "
<<
to_string
(
self
->
last_dequeued
())
<<
endl
;
}
)
;
}
;
}
void
tester
(
event_based_actor
*
self
,
const
actor
&
testee
)
{
...
...
@@ -59,15 +54,14 @@ void tester(event_based_actor* self, const actor& testee) {
self
->
quit
(
exit_reason
::
user_shutdown
);
});
// first test: 2 + 1 = 3
self
->
sync_send
(
testee
,
atom
(
"plus"
)
,
2
,
1
).
then
(
on
(
atom
(
"result"
),
3
)
>>
[
=
]
{
self
->
sync_send
(
testee
,
plus_atom
::
value
,
2
,
1
).
then
(
on
(
3
)
>>
[
=
]
{
// second test: 2 - 1 = 1
self
->
sync_send
(
testee
,
atom
(
"minus"
)
,
2
,
1
).
then
(
on
(
atom
(
"result"
),
1
)
>>
[
=
]
{
self
->
sync_send
(
testee
,
minus_atom
::
value
,
2
,
1
).
then
(
on
(
1
)
>>
[
=
]
{
// both tests succeeded
aout
(
self
)
<<
"AUT (actor under test) seems to be ok"
<<
endl
;
self
->
send
(
testee
,
atom
(
"quit"
));
aout
(
self
)
<<
"AUT (actor under test) seems to be ok"
<<
endl
;
self
->
quit
(
exit_reason
::
user_shutdown
);
}
);
}
...
...
@@ -75,8 +69,11 @@ void tester(event_based_actor* self, const actor& testee) {
}
int
main
()
{
cout
<<
"test blocking actor"
<<
endl
;
spawn
(
tester
,
spawn
<
blocking_api
>
(
blocking_calculator
));
await_all_actors_done
();
cout
<<
"test event-based actor"
<<
endl
;
spawn
(
tester
,
spawn
(
calculator
));
await_all_actors_done
();
shutdown
();
return
0
;
}
examples/message_passing/dancing_kirby.cpp
View file @
a6cb56a0
...
...
@@ -13,6 +13,8 @@ using std::pair;
using
namespace
caf
;
using
step_atom
=
atom_constant
<
atom
(
"step"
)
>
;
// ASCII art figures
constexpr
const
char
*
figures
[]
=
{
"<(^.^<)"
,
...
...
@@ -30,11 +32,6 @@ constexpr animation_step animation_steps[] = {
{
0
,
12
},
{
0
,
11
},
{
0
,
10
},
{
0
,
9
},
{
0
,
8
},
{
0
,
7
},
{
1
,
7
}
};
template
<
class
T
,
size_t
S
>
constexpr
size_t
array_size
(
const
T
(
&
)
[
S
])
{
return
S
;
}
constexpr
size_t
animation_width
=
20
;
// "draws" an animation step by printing "{offset_whitespaces}{figure}{padding}"
...
...
@@ -55,19 +52,20 @@ void draw_kirby(const animation_step& animation) {
// uses a message-based loop to iterate over all animation steps
void
dancing_kirby
(
event_based_actor
*
self
)
{
// let's get it started
self
->
send
(
self
,
atom
(
"Step"
)
,
size_t
{
0
});
self
->
send
(
self
,
step_atom
::
value
,
size_t
{
0
});
self
->
become
(
on
(
atom
(
"Step"
),
array_size
(
animation_steps
))
>>
[
=
]
{
// we've printed all animation steps (done)
cout
<<
endl
;
self
->
quit
();
},
on
(
atom
(
"Step"
),
arg_match
)
>>
[
=
](
size_t
step
)
{
[
=
](
step_atom
,
size_t
step
)
{
if
(
step
==
sizeof
(
animation_step
))
{
// we've printed all animation steps (done)
cout
<<
endl
;
self
->
quit
();
return
;
}
// print given step
draw_kirby
(
animation_steps
[
step
]);
// animate next step in 150ms
self
->
delayed_send
(
self
,
std
::
chrono
::
milliseconds
(
150
),
atom
(
"Step"
)
,
step
+
1
);
step_atom
::
value
,
step
+
1
);
}
);
}
...
...
@@ -76,5 +74,4 @@ int main() {
spawn
(
dancing_kirby
);
await_all_actors_done
();
shutdown
();
return
0
;
}
examples/message_passing/dining_philosophers.cpp
View file @
a6cb56a0
...
...
@@ -18,160 +18,176 @@ using namespace caf;
namespace
{
// atoms for chopstick interface
using
put_atom
=
atom_constant
<
atom
(
"put"
)
>
;
using
take_atom
=
atom_constant
<
atom
(
"take"
)
>
;
using
busy_atom
=
atom_constant
<
atom
(
"busy"
)
>
;
using
taken_atom
=
atom_constant
<
atom
(
"taken"
)
>
;
// atoms for philosopher interface
using
eat_atom
=
atom_constant
<
atom
(
"eat"
)
>
;
using
think_atom
=
atom_constant
<
atom
(
"think"
)
>
;
// a chopstick
using
chopstick
=
typed_actor
<
replies_to
<
take_atom
>
::
with_either
<
taken_atom
>
::
or_else
<
busy_atom
>
,
reacts_to
<
put_atom
>>
;
chopstick
::
behavior_type
taken_chopstick
(
chopstick
::
pointer
self
,
actor_addr
);
// either taken by a philosopher or available
void
chopstick
(
event_based_actor
*
self
)
{
self
->
become
(
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
const
actor
&
philos
)
{
// tell philosopher it took this chopstick
self
->
send
(
philos
,
atom
(
"taken"
),
self
);
// await 'put' message and reject other 'take' messages
self
->
become
(
// allows us to return to the previous behavior
keep_behavior
,
on
(
atom
(
"take"
),
arg_match
)
>>
[
=
](
const
actor
&
other
)
{
self
->
send
(
other
,
atom
(
"busy"
),
self
);
},
on
(
atom
(
"put"
),
philos
)
>>
[
=
]
{
// return to previous behaivor, i.e., await next 'take'
self
->
unbecome
();
}
);
chopstick
::
behavior_type
available_chopstick
(
chopstick
::
pointer
self
)
{
return
{
[
=
](
take_atom
)
{
self
->
become
(
taken_chopstick
(
self
,
self
->
last_sender
()));
return
taken_atom
::
value
;
},
[](
put_atom
)
{
cerr
<<
"chopstick received unexpected 'put'"
<<
endl
;
}
)
;
}
;
}
/* See: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/
chopstick
::
behavior_type
taken_chopstick
(
chopstick
::
pointer
self
,
actor_addr
user
)
{
return
{
[](
take_atom
)
{
return
busy_atom
::
value
;
},
[
=
](
put_atom
)
{
if
(
self
->
last_sender
()
==
user
)
{
self
->
become
(
available_chopstick
(
self
));
}
}
};
}
/* Based on: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/
*
*
* +-------------+
{(busy|taken), Y
}
* +-------------+
{busy|taken
}
* /-------->| thinking |<------------------\
* | +-------------+ |
* | | |
* | | {eat} |
* | | |
* | V |
* | +-------------+
{busy, X}
+-------------+
* | +-------------+
{busy}
+-------------+
* | | hungry |----------->| denied |
* | +-------------+ +-------------+
* | |
* | | {taken
, X
}
* | | {taken}
* | |
* | V
* | +-------------+
* | |
wait_for(Y)
|
* | |
granted
|
* | +-------------+
* | | |
* |
{busy, Y} | | {taken, Y
}
* |
{busy} | | {taken
}
* \-----------/ |
* | V
* | {think} +-------------+
* \---------| eating |
* +-------------+
*
*
* [ X = left => Y = right ]
* [ X = right => Y = left ]
*/
class
philosopher
:
public
event_based_actor
{
public:
philosopher
(
const
std
::
string
&
n
,
const
actor
&
l
,
const
actor
&
r
)
:
name
(
n
),
left
(
l
),
right
(
r
)
{
philosopher
(
const
std
::
string
&
n
,
const
chopstick
&
l
,
const
chopstick
&
r
)
:
name
(
n
),
left
(
l
),
right
(
r
)
{
// a philosopher that receives {eat} stops thinking and becomes hungry
thinking
=
(
on
(
atom
(
"eat"
))
>>
[
=
]
{
thinking
=
behavior
{
[
=
](
eat_atom
)
{
become
(
hungry
);
send
(
left
,
atom
(
"take"
),
this
);
send
(
right
,
atom
(
"take"
),
this
);
send
(
left
,
take_atom
::
value
);
send
(
right
,
take_atom
::
value
);
}
)
;
}
;
// wait for the first answer of a chopstick
hungry
=
(
on
(
atom
(
"taken"
),
left
)
>>
[
=
]
{
become
(
waiting_for
(
right
));
},
on
(
atom
(
"taken"
),
right
)
>>
[
=
]
{
become
(
waiting_for
(
left
));
hungry
=
behavior
{
[
=
](
taken_atom
)
{
become
(
granted
);
},
on
<
atom
(
"busy"
),
actor
>
()
>>
[
=
]
{
[
=
](
busy_atom
)
{
become
(
denied
);
}
);
// philosopher was not able to obtain the first chopstick
denied
=
(
on
(
atom
(
"taken"
),
arg_match
)
>>
[
=
](
const
actor
&
ptr
)
{
send
(
ptr
,
atom
(
"put"
),
this
);
send
(
this
,
atom
(
"eat"
));
};
// philosopher was able to obtain the first chopstick
granted
=
behavior
{
[
=
](
taken_atom
)
{
aout
(
this
)
<<
name
<<
" has picked up chopsticks with IDs "
<<
left
->
id
()
<<
" and "
<<
right
->
id
()
<<
" and starts to eat
\n
"
;
// eat some time
delayed_send
(
this
,
seconds
(
5
),
think_atom
::
value
);
become
(
eating
);
},
[
=
](
busy_atom
)
{
send
(
last_sender
()
==
left
?
right
:
left
,
put_atom
::
value
);
send
(
this
,
eat_atom
::
value
);
become
(
thinking
);
}
};
// philosopher was *not* able to obtain the first chopstick
denied
=
behavior
{
[
=
](
taken_atom
)
{
send
(
last_sender
()
==
left
?
left
:
right
,
put_atom
::
value
);
send
(
this
,
eat_atom
::
value
);
become
(
thinking
);
},
on
<
atom
(
"busy"
),
actor
>
()
>>
[
=
]
{
send
(
this
,
atom
(
"eat"
)
);
[
=
](
busy_atom
)
{
send
(
this
,
eat_atom
::
value
);
become
(
thinking
);
}
)
;
}
;
// philosopher obtained both chopstick and eats (for five seconds)
eating
=
(
on
(
atom
(
"think"
))
>>
[
=
]
{
send
(
left
,
atom
(
"put"
),
this
);
send
(
right
,
atom
(
"put"
),
this
);
delayed_send
(
this
,
seconds
(
5
),
atom
(
"eat"
)
);
eating
=
behavior
{
[
=
](
think_atom
)
{
send
(
left
,
put_atom
::
value
);
send
(
right
,
put_atom
::
value
);
delayed_send
(
this
,
seconds
(
5
),
eat_atom
::
value
);
aout
(
this
)
<<
name
<<
" puts down his chopsticks and starts to think
\n
"
;
become
(
thinking
);
}
)
;
}
;
}
protected:
behavior
make_behavior
()
override
{
// start thinking
send
(
this
,
atom
(
"think"
)
);
send
(
this
,
think_atom
::
value
);
// philosophers start to think after receiving {think}
return
(
on
(
atom
(
"think"
))
>>
[
=
]
{
[
=
](
think_atom
)
{
aout
(
this
)
<<
name
<<
" starts to think
\n
"
;
delayed_send
(
this
,
seconds
(
5
),
atom
(
"eat"
)
);
delayed_send
(
this
,
seconds
(
5
),
eat_atom
::
value
);
become
(
thinking
);
}
);
}
private:
// wait for second chopstick
behavior
waiting_for
(
const
actor
&
what
)
{
return
{
on
(
atom
(
"taken"
),
what
)
>>
[
=
]
{
aout
(
this
)
<<
name
<<
" has picked up chopsticks with IDs "
<<
left
->
id
()
<<
" and "
<<
right
->
id
()
<<
" and starts to eat
\n
"
;
// eat some time
delayed_send
(
this
,
seconds
(
5
),
atom
(
"think"
));
become
(
eating
);
},
on
(
atom
(
"busy"
),
what
)
>>
[
=
]
{
send
((
what
==
left
)
?
right
:
left
,
atom
(
"put"
),
this
);
send
(
this
,
atom
(
"eat"
));
become
(
thinking
);
}
};
}
std
::
string
name
;
// the name of this philosopher
actor
left
;
// left chopstick
actor
right
;
// right chopstick
behavior
thinking
;
behavior
hungry
;
// tries to take chopsticks
behavior
denied
;
// could not get chopsticks
behavior
eating
;
// wait for some time, then go thinking again
std
::
string
name
;
// the name of this philosopher
chopstick
left
;
// left chopstick
chopstick
right
;
// right chopstick
behavior
thinking
;
// initial behavior
behavior
hungry
;
// tries to take chopsticks
behavior
granted
;
// has one chopstick and waits for the second one
behavior
denied
;
// could not get first chopsticks
behavior
eating
;
// waits for some time, then go thinking again
};
void
dining_philosophers
()
{
scoped_actor
self
;
// create five chopsticks
aout
(
self
)
<<
"chopstick ids are:"
;
std
::
vector
<
actor
>
chopsticks
;
std
::
vector
<
chopstick
>
chopsticks
;
for
(
size_t
i
=
0
;
i
<
5
;
++
i
)
{
chopsticks
.
push_back
(
spawn
(
chopstick
));
chopsticks
.
push_back
(
spawn
_typed
(
available_
chopstick
));
aout
(
self
)
<<
" "
<<
chopsticks
.
back
()
->
id
();
}
aout
(
self
)
<<
endl
;
...
...
@@ -190,5 +206,4 @@ int main(int, char**) {
// real philosophers are never done
await_all_actors_done
();
shutdown
();
return
0
;
}
examples/remote_actors/distributed_calculator.cpp
View file @
a6cb56a0
...
...
@@ -27,17 +27,21 @@
using
namespace
std
;
using
namespace
caf
;
using
plus_atom
=
atom_constant
<
atom
(
"plus"
)
>
;
using
minus_atom
=
atom_constant
<
atom
(
"minus"
)
>
;
using
result_atom
=
atom_constant
<
atom
(
"result"
)
>
;
using
rebind_atom
=
atom_constant
<
atom
(
"rebind"
)
>
;
using
connect_atom
=
atom_constant
<
atom
(
"connect"
)
>
;
using
reconnect_atom
=
atom_constant
<
atom
(
"reconnect"
)
>
;
// our "service"
void
calculator
(
event_based_actor
*
self
)
{
self
->
become
(
on
(
atom
(
"plus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
->
message
{
return
make_message
(
atom
(
"result"
),
a
+
b
);
},
on
(
atom
(
"minus"
),
arg_match
)
>>
[](
int
a
,
int
b
)
->
message
{
return
make_message
(
atom
(
"result"
),
a
-
b
);
[](
plus_atom
,
int
a
,
int
b
)
->
message
{
return
make_message
(
result_atom
::
value
,
a
+
b
);
},
on
(
atom
(
"quit"
))
>>
[
=
]
{
self
->
quit
(
);
[](
minus_atom
,
int
a
,
int
b
)
->
message
{
return
make_message
(
result_atom
::
value
,
a
-
b
);
}
);
}
...
...
@@ -57,7 +61,7 @@ void client_bhvr(event_based_actor* self, const string& host,
if
(
!
self
->
has_sync_failure_handler
())
{
self
->
on_sync_failure
([
=
]
{
aout
(
self
)
<<
"*** lost connection to "
<<
host
<<
":"
<<
port
<<
endl
;
<<
":"
<<
port
<<
endl
;
client_bhvr
(
self
,
host
,
port
,
invalid_actor
);
});
}
...
...
@@ -73,38 +77,33 @@ void client_bhvr(event_based_actor* self, const string& host,
}
catch
(
exception
&
)
{
aout
(
self
)
<<
"connection failed, try again in 3s"
<<
endl
;
self
->
delayed_send
(
self
,
chrono
::
seconds
(
3
),
atom
(
"reconnect"
)
);
self
->
delayed_send
(
self
,
chrono
::
seconds
(
3
),
reconnect_atom
::
value
);
}
}
// our predicate guarding the first callback
auto
pred
=
[
=
](
atom_value
val
)
->
optional
<
atom_value
>
{
if
(
server
!=
invalid_actor
&&
(
val
==
atom
(
"plus"
)
||
val
==
atom
(
"minus"
)))
{
return
val
;
}
return
none
;
auto
sync_send_request
=
[
=
](
int
lhs
,
const
char
*
op
,
int
rhs
)
{
self
->
sync_send_tuple
(
server
,
self
->
last_dequeued
()).
then
(
[
=
](
result_atom
,
int
result
)
{
aout
(
self
)
<<
lhs
<<
" "
<<
op
<<
" "
<<
rhs
<<
" = "
<<
result
<<
endl
;
}
);
};
self
->
become
(
on
(
pred
,
val
<
int
>
,
val
<
int
>
)
>>
[
=
](
atom_value
op
,
int
lhs
,
int
rhs
)
{
self
->
sync_send_tuple
(
server
,
self
->
last_dequeued
()).
then
(
on
(
atom
(
"result"
),
arg_match
)
>>
[
=
](
int
result
)
{
aout
(
self
)
<<
lhs
<<
" "
<<
to_string
(
op
)
<<
" "
<<
rhs
<<
" = "
<<
result
<<
endl
;
}
);
[
=
](
plus_atom
,
int
lhs
,
int
rhs
)
{
sync_send_request
(
lhs
,
"+"
,
rhs
);
},
[
=
](
minus_atom
,
int
lhs
,
int
rhs
)
{
sync_send_request
(
lhs
,
"-"
,
rhs
);
},
[
=
](
const
down_msg
&
)
{
aout
(
self
)
<<
"*** server down, try to reconnect ..."
<<
endl
;
client_bhvr
(
self
,
host
,
port
,
invalid_actor
);
},
on
(
atom
(
"rebind"
),
arg_match
)
>>
[
=
](
const
string
&
nhost
,
uint16_t
nport
)
{
[
=
](
rebind_atom
,
const
string
&
nhost
,
uint16_t
nport
)
{
aout
(
self
)
<<
"*** rebind to new server: "
<<
nhost
<<
":"
<<
nport
<<
endl
;
client_bhvr
(
self
,
nhost
,
nport
,
invalid_actor
);
},
on
(
atom
(
"reconnect"
))
>>
[
=
]
{
[
=
](
rebind_atom
)
{
client_bhvr
(
self
,
host
,
port
,
invalid_actor
);
}
);
...
...
@@ -133,8 +132,8 @@ void client_repl(const string& host, uint16_t port) {
try
{
auto
lport
=
std
::
stoul
(
sport
);
if
(
lport
<
std
::
numeric_limits
<
uint16_t
>::
max
())
{
anon_send
(
client
,
atom
(
"rebind"
)
,
move
(
nhost
),
static_cast
<
uint16_t
>
(
lport
));
anon_send
(
client
,
rebind_atom
::
value
,
move
(
nhost
),
static_cast
<
uint16_t
>
(
lport
));
}
else
{
cout
<<
lport
<<
" is not a valid port"
<<
endl
;
...
...
@@ -167,7 +166,7 @@ void client_repl(const string& host, uint16_t port) {
auto
lhs
=
toint
(
lsub
);
auto
rhs
=
toint
(
rsub
);
if
(
lhs
&&
rhs
)
{
auto
op
=
(
*
pos
==
'+'
)
?
atom
(
"plus"
)
:
atom
(
"minus"
)
;
auto
op
=
(
*
pos
==
'+'
)
?
plus_atom
::
value
:
minus_atom
::
value
;
anon_send
(
client
,
op
,
*
lhs
,
*
rhs
);
}
}
...
...
examples/remote_actors/group_chat.cpp
View file @
a6cb56a0
...
...
@@ -24,6 +24,9 @@
using
namespace
std
;
using
namespace
caf
;
using
join_atom
=
atom_constant
<
atom
(
"join"
)
>
;
using
broadcast_atom
=
atom_constant
<
atom
(
"broadcast"
)
>
;
struct
line
{
string
str
;
};
istream
&
operator
>>
(
istream
&
is
,
line
&
l
)
{
...
...
@@ -46,12 +49,12 @@ message split_line(const line& l) {
void
client
(
event_based_actor
*
self
,
const
string
&
name
)
{
self
->
become
(
on
(
atom
(
"broadcast"
),
arg_match
)
>>
[
=
](
const
string
&
message
)
{
[
=
](
broadcast_atom
,
const
string
&
message
)
{
for
(
auto
&
dest
:
self
->
joined_groups
())
{
self
->
send
(
dest
,
name
+
": "
+
message
);
}
},
on
(
atom
(
"join"
),
arg_match
)
>>
[
=
](
const
group
&
what
)
{
[
=
](
join_atom
,
const
group
&
what
)
{
for
(
auto
g
:
self
->
joined_groups
())
{
cout
<<
"*** leave "
<<
to_string
(
g
)
<<
endl
;
self
->
send
(
self
,
g
,
name
+
" has left the chatroom"
);
...
...
@@ -106,7 +109,7 @@ int main(int argc, char** argv) {
auto
group_uri
=
group_id
.
substr
(
p
+
1
);
auto
g
=
(
module
==
"remote"
)
?
io
::
remote_group
(
group_uri
)
:
group
::
get
(
module
,
group_uri
);
anon_send
(
client_actor
,
atom
(
"join"
)
,
g
);
anon_send
(
client_actor
,
join_atom
::
value
,
g
);
}
catch
(
exception
&
e
)
{
ostringstream
err
;
...
...
@@ -132,7 +135,7 @@ int main(int argc, char** argv) {
try
{
group
grp
=
(
mod
==
"remote"
)
?
io
::
remote_group
(
id
)
:
group
::
get
(
mod
,
id
);
anon_send
(
client_actor
,
atom
(
"join"
)
,
grp
);
anon_send
(
client_actor
,
join_atom
::
value
,
grp
);
}
catch
(
exception
&
e
)
{
cerr
<<
"*** exception: "
<<
to_verbose_string
(
e
)
<<
endl
;
...
...
@@ -150,7 +153,7 @@ int main(int argc, char** argv) {
},
others
()
>>
[
&
]
{
if
(
!
s_last_line
.
empty
())
{
anon_send
(
client_actor
,
atom
(
"broadcast"
)
,
s_last_line
);
anon_send
(
client_actor
,
broadcast_atom
::
value
,
s_last_line
);
}
}
);
...
...
@@ -158,5 +161,4 @@ int main(int argc, char** argv) {
anon_send_exit
(
client_actor
,
exit_reason
::
user_shutdown
);
await_all_actors_done
();
shutdown
();
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment