Commit c3beb4d6 authored by Dominik Charousset's avatar Dominik Charousset

revamped spawn to use event-based impl by default

this patch turns libcppa's spawn function family upside down;
actors are now event-based by default, but users can opt out
by using `spawn<blocking_api>(...)`;
this patch also removes the old `scheduling_hint` interface and
replaces it with the more versatile `spawn_options`, e.g.,
`spawn_monitor<detached>(...)` becomes `spawn<monitored + detached>(...)`
parent 55bc8869
......@@ -125,7 +125,6 @@ cppa/response_handle.hpp
cppa/sb_actor.hpp
cppa/scheduled_actor.hpp
cppa/scheduler.hpp
cppa/scheduling_hint.hpp
cppa/self.hpp
cppa/serializer.hpp
cppa/thread_mapped_actor.hpp
......@@ -293,3 +292,4 @@ cppa/memory_cached_mixin.hpp
unit_testing/test.cpp
src/exit_reason.cpp
src/on.cpp
cppa/spawn_options.hpp
......@@ -37,6 +37,7 @@
#include "cppa/group.hpp"
#include "cppa/channel.hpp"
#include "cppa/cppa_fwd.hpp"
#include "cppa/attachable.hpp"
#include "cppa/message_id.hpp"
......
This diff is collapsed.
......@@ -104,8 +104,10 @@ class event_based_actor_factory {
template<typename... Args>
actor_ptr spawn(Args&&... args) {
return get_scheduler()->spawn(memory::create<impl>(m_init, m_on_exit,
std::forward<Args>(args)...));
auto ptr = memory::create<impl>(m_init,
m_on_exit,
std::forward<Args>(args)...);
return get_scheduler()->exec(no_spawn_options, ptr);
}
private:
......
......@@ -47,31 +47,24 @@ class thread_pool_scheduler : public scheduler {
public:
using scheduler::init_callback;
using scheduler::void_function;
struct worker;
thread_pool_scheduler();
thread_pool_scheduler(size_t num_worker_threads);
void initialize() /*override*/;
void destroy() /*override*/;
void enqueue(scheduled_actor* what) /*override*/;
void initialize();
actor_ptr spawn(scheduled_actor* what,
scheduling_hint hint);
void destroy();
actor_ptr spawn(scheduled_actor* what,
init_callback init_cb,
scheduling_hint hint);
void enqueue(scheduled_actor* what);
actor_ptr spawn(void_function fun,
scheduling_hint hint);
actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr);
actor_ptr spawn(void_function what,
init_callback init_cb,
scheduling_hint hint);
actor_ptr exec(spawn_options opts, init_callback init_cb, void_function f);
private:
......@@ -86,10 +79,6 @@ class thread_pool_scheduler : public scheduler {
static void worker_loop(worker*);
static void supervisor_loop(job_queue*, scheduled_actor*, size_t);
actor_ptr spawn_impl(scheduled_actor_ptr what);
actor_ptr spawn_as_thread(void_function fun, init_callback cb, bool hidden);
};
} } // namespace cppa::detail
......
......@@ -87,6 +87,8 @@ class event_based_actor : public detail::abstract_scheduled_actor {
scheduled_actor_type impl_type();
static intrusive_ptr<event_based_actor> from(std::function<void()> fun);
protected:
event_based_actor();
......
......@@ -31,6 +31,8 @@
#ifndef CPPA_ACTOR_BEHAVIOR_HPP
#define CPPA_ACTOR_BEHAVIOR_HPP
#include <functional>
#include "cppa/config.hpp"
#include "cppa/local_actor.hpp"
......@@ -46,7 +48,8 @@ enum class resume_result {
enum scheduled_actor_type {
context_switching_impl,
event_based_impl
event_based_impl,
default_event_based_impl // scheduler enqueues a 'RUN' message on startup
};
/**
......
......@@ -35,6 +35,7 @@
#include <memory>
#include <cstdint>
#include <functional>
#include <type_traits>
#include "cppa/atom.hpp"
#include "cppa/actor.hpp"
......@@ -42,32 +43,32 @@
#include "cppa/cow_tuple.hpp"
#include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/scheduling_hint.hpp"
#include "cppa/spawn_options.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/util/duration.hpp"
namespace cppa {
class self_type;
class scheduled_actor;
class scheduler_helper;
typedef std::function<void()> void_function;
typedef std::function<void(local_actor*)> init_callback;
namespace detail { class singleton_manager; } // namespace detail
namespace detail {
// forwards self_type as actor_ptr, otherwise equal to std::forward
template<typename T>
struct spawn_fwd_ {
static inline T&& _(T&& arg) { return std::move(arg); }
static inline T& _(T& arg) { return arg; }
static inline const T& _(const T& arg) { return arg; }
};
template<>
struct spawn_fwd_<self_type> {
static inline actor_ptr _(const self_type& s) { return s.get(); }
struct is_self {
typedef typename util::rm_ref<T>::type plain_type;
static constexpr bool value = std::is_same<plain_type,self_type>::value;
};
class singleton_manager;
template<typename T, typename U>
auto fwd(U& arg, typename std::enable_if<!is_self<T>::value>::type* = 0)
-> decltype(std::forward<T>(arg)) {
return std::forward<T>(arg);
}
template<typename T, typename U>
local_actor* fwd(U& arg, typename std::enable_if<is_self<T>::value>::type* = 0){
return arg;
}
} // namespace detail
/**
......@@ -107,6 +108,9 @@ class scheduler {
public:
typedef std::function<void(local_actor*)> init_callback;
typedef std::function<void()> void_function;
const actor_ptr& printer() const;
virtual void enqueue(scheduled_actor*) = 0;
......@@ -157,72 +161,26 @@ class scheduler {
}
/**
* @brief Spawns a new actor that executes <code>fun()</code>
* with the scheduling policy @p hint if possible.
*/
virtual actor_ptr spawn(void_function fun, scheduling_hint hint) = 0;
/**
* @brief Spawns a new actor that executes <code>behavior()</code>
* with the scheduling policy @p hint if possible and calls
* <code>init_cb</code> after the actor is initialized but before
* it starts execution.
* @brief Executes @p ptr in this scheduler.
*/
virtual actor_ptr spawn(void_function fun,
init_callback init_cb,
scheduling_hint hint) = 0;
virtual actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr) = 0;
/**
* @brief Spawns a new event-based actor.
* @brief Creates a new actor from @p actor_behavior and executes it
* in this scheduler.
*/
virtual actor_ptr spawn(scheduled_actor* what,
scheduling_hint hint = scheduled) = 0;
/**
* @brief Spawns a new event-based actor and calls
* <code>init_cb</code> after the actor is initialized but before
* it starts execution.
*/
virtual actor_ptr spawn(scheduled_actor* what,
init_callback init_cb,
scheduling_hint hint = scheduled) = 0;
virtual actor_ptr exec(spawn_options opts,
init_callback init_cb,
void_function actor_behavior) = 0;
// hide implementation details for documentation
# ifndef CPPA_DOCUMENTATION
template<typename Fun, typename Arg0, typename... Args>
actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun, Arg0&& arg0, Args&&... args) {
return this->spawn(
std::bind(
std::forward<Fun>(fun),
detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
hint);
}
template<typename Fun>
actor_ptr spawn_impl(scheduling_hint hint, Fun&& fun) {
return this->spawn(std::forward<Fun>(fun), hint);
}
template<typename InitCallback, typename Fun, typename Arg0, typename... Args>
actor_ptr spawn_cb_impl(scheduling_hint hint,
InitCallback&& init_cb,
Fun&& fun, Arg0&& arg0, Args&&... args) {
return this->spawn(
std::bind(
std::forward<Fun>(fun),
detail::spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
detail::spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...),
std::forward<InitCallback>(init_cb),
hint);
}
template<typename InitCallback, typename Fun>
actor_ptr spawn_cb_impl(scheduling_hint hint, InitCallback&& init_cb, Fun&& fun) {
return this->spawn(std::forward<Fun>(fun),
std::forward<InitCallback>(init_cb),
hint);
template<typename F, typename T0, typename... Ts>
actor_ptr exec(spawn_options opts, init_callback cb,
F f, T0&& a0, Ts&&... as) {
return this->exec(opts, cb, std::bind(f, detail::fwd<T0>(a0),
detail::fwd<Ts>(as)...));
}
# endif // CPPA_DOCUMENTATION
......
......@@ -28,41 +28,130 @@
\******************************************************************************/
#ifndef CPPA_SCHEDULING_HINT_HPP
#define CPPA_SCHEDULING_HINT_HPP
#ifndef CPPA_SPAWN_OPTIONS_HPP
#define CPPA_SPAWN_OPTIONS_HPP
namespace cppa {
/**
* @brief Denotes whether a user wants an actor to take part in
* cooperative scheduling or not.
* @ingroup ActorCreation
* @{
*/
enum scheduling_hint {
/**
* @brief Indicates that an actor takes part in cooperative scheduling.
*/
scheduled,
/**
* @brief Indicates that an actor should run in its own thread.
*/
detached,
/**
* @brief Indicates that an actor should run in its own thread,
* but it is ignored by {@link await_others_done()}.
*/
detached_and_hidden,
/**
* @brief Indicates that an actor takes part in cooperative scheduling,
* but it is ignored by {@link await_others_done()}.
*/
scheduled_and_hidden
/**
* @brief Stores options passed to the @p spawn function family.
*/
enum class spawn_options : int {
no_flags = 0x00,
link_flag = 0x01,
monitor_flag = 0x02,
detach_flag = 0x04,
hide_flag = 0x08,
blocking_api_flag = 0x10
};
#ifndef CPPA_DOCUMENTATION
namespace {
#endif
/**
* @brief Denotes default settings.
*/
constexpr spawn_options no_spawn_options = spawn_options::no_flags;
/**
* @brief Causes @p spawn to call <tt>self->monitor(...)</tt> immediately
* after the new actor was spawned.
*/
constexpr spawn_options monitored = spawn_options::monitor_flag;
/**
* @brief Causes @p spawn to call <tt>self->link_to(...)</tt> immediately
* after the new actor was spawned.
*/
constexpr spawn_options linked = spawn_options::link_flag;
/**
* @brief Causes the new actor to opt out of the cooperative scheduling.
*/
constexpr spawn_options detached = spawn_options::detach_flag;
/**
* @brief Causes the runtime to ignore the new actor in
* {@link await_all_others_done()}.
*/
constexpr spawn_options hidden = spawn_options::hide_flag;
/**
* @brief Causes the new actor to opt in to the blocking API of libcppa,
* i.e., the actor uses a context-switching or thread-based backend
* instead of the default event-based implementation.
*/
constexpr spawn_options blocking_api = spawn_options::blocking_api_flag;
#ifndef CPPA_DOCUMENTATION
} // namespace <anonymous>
#endif
/**
* @brief Concatenates two {@link spawn_options}.
* @relates spawn_options
*/
constexpr spawn_options operator+(const spawn_options& lhs,
const spawn_options& rhs) {
return static_cast<spawn_options>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
/**
* @brief Checks wheter @p haystack contains @p needle.
* @relates spawn_options
*/
constexpr bool has_spawn_option(spawn_options haystack, spawn_options needle) {
return (static_cast<int>(haystack) & static_cast<int>(needle)) != 0;
}
/**
* @brief Checks wheter the {@link detached} flag is set in @p opts.
* @relates spawn_options
*/
constexpr bool has_detach_flag(spawn_options opts) {
return has_spawn_option(opts, detached);
}
/**
* @brief Checks wheter the {@link hidden} flag is set in @p opts.
* @relates spawn_options
*/
constexpr bool has_hide_flag(spawn_options opts) {
return has_spawn_option(opts, hidden);
}
/**
* @brief Checks wheter the {@link linked} flag is set in @p opts.
* @relates spawn_options
*/
constexpr bool has_link_flag(spawn_options opts) {
return has_spawn_option(opts, linked);
}
/**
* @brief Checks wheter the {@link monitored} flag is set in @p opts.
* @relates spawn_options
*/
constexpr bool has_monitor_flag(spawn_options opts) {
return has_spawn_option(opts, monitored);
}
/**
* @brief Checks wheter the {@link blocking_api} flag is set in @p opts.
* @relates spawn_options
*/
constexpr bool has_blocking_api_flag(spawn_options opts) {
return has_spawn_option(opts, blocking_api);
}
/** @} */
} // namespace cppa
#endif // CPPA_SCHEDULING_HINT_HPP
#endif // CPPA_SPAWN_OPTIONS_HPP
......@@ -17,33 +17,25 @@ using namespace std;
using namespace cppa;
// either taken by a philosopher or available
struct chopstick : sb_actor<chopstick> {
behavior& init_state; // a reference to available
behavior available;
behavior taken_by(const actor_ptr& philos) {
// create a behavior new on-the-fly
return (
on<atom("take"), actor_ptr>() >> [=](actor_ptr other) {
send(other, atom("busy"), this);
},
on(atom("put"), philos) >> [=]() {
become(available);
}
);
}
chopstick() : init_state(available) {
available = (
on<atom("take"), actor_ptr>() >> [=](actor_ptr philos) {
send(philos, atom("taken"), this);
become(taken_by(philos));
}
);
}
};
void chopstick() {
become(
on(atom("take"), arg_match) >> [=](const actor_ptr& philos) {
// tell philosopher it took this chopstick
send(philos, atom("taken"), self);
// await 'put' message and reject other 'take' messages
become(
keep_behavior, // "enables" unbecome()
on(atom("take"), arg_match) >> [=](const actor_ptr& other) {
send(other, atom("busy"), self);
},
on(atom("put"), philos) >> [=] {
// return to previous behaivor, i.e., await next 'take'
unbecome();
}
);
}
);
}
/* See: http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/
*
......@@ -95,10 +87,7 @@ struct philosopher : sb_actor<philosopher> {
// wait for second chopstick
behavior waiting_for(const actor_ptr& what) {
return (
on(atom("taken"), what) >> [=]() {
// create message in memory to avoid interleaved
// messages on the terminal
std::ostringstream oss;
on(atom("taken"), what) >> [=] {
aout << name
<< " has picked up chopsticks with IDs "
<< left->id()
......@@ -109,7 +98,7 @@ struct philosopher : sb_actor<philosopher> {
delayed_send(this, seconds(5), atom("think"));
become(eating);
},
on(atom("busy"), what) >> [=]() {
on(atom("busy"), what) >> [=] {
send((what == left) ? right : left, atom("put"), this);
send(this, atom("eat"));
become(thinking);
......@@ -121,7 +110,7 @@ struct philosopher : sb_actor<philosopher> {
: name(n), left(l), right(r) {
// a philosopher that receives {eat} stops thinking and becomes hungry
thinking = (
on(atom("eat")) >> [=]() {
on(atom("eat")) >> [=] {
become(hungry);
send(left, atom("take"), this);
send(right, atom("take"), this);
......@@ -129,43 +118,43 @@ struct philosopher : sb_actor<philosopher> {
);
// wait for the first answer of a chopstick
hungry = (
on(atom("taken"), left) >> [=]() {
on(atom("taken"), left) >> [=] {
become(waiting_for(right));
},
on(atom("taken"), right) >> [=]() {
on(atom("taken"), right) >> [=] {
become(waiting_for(left));
},
on<atom("busy"), actor_ptr>() >> [=]() {
on<atom("busy"), actor_ptr>() >> [=] {
become(denied);
}
);
// philosopher was not able to obtain the first chopstick
denied = (
on<atom("taken"), actor_ptr>() >> [=](actor_ptr& ptr) {
on(atom("taken"), arg_match) >> [=](const actor_ptr& ptr) {
send(ptr, atom("put"), this);
send(this, atom("eat"));
become(thinking);
},
on<atom("busy"), actor_ptr>() >> [=]() {
on<atom("busy"), actor_ptr>() >> [=] {
send(this, atom("eat"));
become(thinking);
}
);
// philosopher obtained both chopstick and eats (for five seconds)
eating = (
on(atom("think")) >> [=]() {
on(atom("think")) >> [=] {
send(left, atom("put"), this);
send(right, atom("put"), this);
delayed_send(this, seconds(5), atom("eat"));
aout << ( name
+ " puts down his chopsticks and starts to think\n");
aout << name
<< " puts down his chopsticks and starts to think\n";
become(thinking);
}
);
// philosophers start to think after receiving {think}
init_state = (
on(atom("think")) >> [=]() {
aout << (name + " starts to think\n");
on(atom("think")) >> [=] {
aout << name << " starts to think\n";
delayed_send(this, seconds(5), atom("eat"));
become(thinking);
}
......@@ -176,10 +165,10 @@ struct philosopher : sb_actor<philosopher> {
int main(int, char**) {
// create five chopsticks
aout << "chopstick ids:";
aout << "chopstick ids are:";
std::vector<actor_ptr> chopsticks;
for (size_t i = 0; i < 5; ++i) {
chopsticks.push_back(spawn<chopstick>());
chopsticks.push_back(spawn(chopstick));
aout << " " << chopsticks.back()->id();
}
aout << endl;
......@@ -194,7 +183,7 @@ int main(int, char**) {
chopsticks[i],
chopsticks[(i+1) % chopsticks.size()]);
}
// tell philosophers to start thinking
// tell all philosophers to start thinking
send(dinner_club, atom("think"));
// real philosophers are never done
await_all_others_done();
......
......@@ -4,35 +4,43 @@
using namespace cppa;
void echo_actor() {
// wait for a message
receive (
void mirror() {
// wait for messages
become (
// invoke this lambda expression if we receive a string
on<std::string>() >> [](const std::string& what) {
on_arg_match >> [](const std::string& what) {
// prints "Hello World!"
std::cout << what << std::endl;
// replies "!dlroW olleH"
reply(std::string(what.rbegin(), what.rend()));
// terminates this actor
self->quit();
}
);
}
int main() {
// create a new actor that invokes the function echo_actor
auto hello_actor = spawn(echo_actor);
// send "Hello World!" to our new actor
// note: libcppa converts string literals to std::string
send(hello_actor, "Hello World!");
// wait for a response and print it
receive (
on<std::string>() >> [](const std::string& what) {
void hello_world(const actor_ptr& buddy) {
// send "Hello World!" to the mirror
send(buddy, "Hello World!");
// wait for messages
become (
on_arg_match >> [](const std::string& what) {
// prints "!dlroW olleH"
std::cout << what << std::endl;
// terminate this actor
self->quit();
}
);
// wait until all other actors we've spawned are done
}
int main() {
// create a new actor that calls 'mirror()'
auto mirror_actor = spawn(mirror);
// create another actor that calls 'hello_world(mirror_actor)'
spawn(hello_world, mirror_actor);
// wait until all other actors we have spawned are done
await_all_others_done();
// done
// run cleanup code before exiting main
shutdown();
return 0;
}
......@@ -13,7 +13,7 @@ using std::endl;
using namespace cppa;
// implementation using the blocking API
void math_fun() {
void blocking_math_fun() {
bool done = false;
do_receive (
// "arg_match" matches the parameter types of given lambda expression
......@@ -23,40 +23,35 @@ void math_fun() {
on(atom("plus"), arg_match) >> [](int a, int b) {
reply(atom("result"), a + b);
},
on<atom("minus"), int, int>() >> [](int a, int b) {
on(atom("minus"), arg_match) >> [](int a, int b) {
reply(atom("result"), a - b);
},
on(atom("quit")) >> [&]() {
// note: quit(exit_reason::normal) would terminate the actor
// but is best avoided since it forces stack unwinding
// by throwing an exception
// note: this actor uses the blocking API, hence self->quit()
// would force stack unwinding by throwing an exception
done = true;
}
)
.until(gref(done));
).until(gref(done));
}
// implementation using the event-based API
struct math_actor : event_based_actor {
void init() {
// execute this behavior until actor terminates
become (
on(atom("plus"), arg_match) >> [](int a, int b) {
reply(atom("result"), a + b);
},
on(atom("minus"), arg_match) >> [](int a, int b) {
reply(atom("result"), a - b);
},
// the [=] capture copies the 'this' pointer into the lambda
// thus, it has access to all members and member functions
on(atom("quit")) >> [=]() {
// set an empty behavior
// (terminates actor with normal exit reason)
quit();
}
);
}
};
void math_fun() {
// execute this behavior until actor terminates
become (
on(atom("plus"), arg_match) >> [](int a, int b) {
reply(atom("result"), a + b);
},
on(atom("minus"), arg_match) >> [](int a, int b) {
reply(atom("result"), a - b);
},
// the [=] capture copies the 'this' pointer into the lambda
// thus, it has access to all members and member functions
on(atom("quit")) >> [=] {
// terminate actor with normal exit reason
self->quit();
}
);
}
// utility function
int fetch_result(actor_ptr& calculator, atom_value operation, int a, int b) {
......@@ -72,9 +67,9 @@ int fetch_result(actor_ptr& calculator, atom_value operation, int a, int b) {
int main() {
// spawn a context-switching actor that invokes math_fun
auto a1 = spawn(math_fun);
auto a1 = spawn<blocking_api>(blocking_math_fun);
// spawn an event-based math actor
auto a2 = spawn<math_actor>();
auto a2 = spawn(math_fun);
// do some testing on both implementations
assert((fetch_result(a1, atom("plus"), 1, 2) == 3));
assert((fetch_result(a2, atom("plus"), 1, 2) == 3));
......
......@@ -31,11 +31,43 @@
#include <iostream>
#include "cppa/to_string.hpp"
#include "cppa/on.hpp"
#include "cppa/self.hpp"
#include "cppa/event_based_actor.hpp"
namespace cppa {
class default_scheduled_actor : public event_based_actor {
public:
typedef std::function<void()> fun_type;
default_scheduled_actor(fun_type&& fun) : m_fun(std::move(fun)) { }
void init() {
become (
on(atom("RUN")) >> [=] {
unbecome();
m_fun();
}
);
}
scheduled_actor_type impl_type() {
return default_event_based_impl;
}
private:
fun_type m_fun;
};
intrusive_ptr<event_based_actor> event_based_actor::from(std::function<void()> fun) {
return detail::memory::create<default_scheduled_actor>(std::move(fun));
}
event_based_actor::event_based_actor() : super(super::blocked) { }
void event_based_actor::dequeue(behavior&) {
......
......@@ -108,7 +108,7 @@ struct group_nameserver : event_based_actor {
};
void publish_local_groups_at(std::uint16_t port, const char* addr) {
auto gn = spawn_hidden<group_nameserver>();
auto gn = spawn<group_nameserver, hidden>();
try {
publish(gn, port, addr);
}
......
......@@ -189,7 +189,7 @@ class local_group_proxy : public local_group {
CPPA_REQUIRE(remote_broker != nullptr);
CPPA_REQUIRE(remote_broker->is_proxy());
m_broker = move(remote_broker);
m_proxy_broker = spawn_hidden<proxy_broker>(this);
m_proxy_broker = spawn<proxy_broker, hidden>(this);
}
group::subscription subscribe(const channel_ptr& who) {
......@@ -426,7 +426,7 @@ class remote_group_module : public group::module {
auto sm = make_counted<shared_map>();
group::module_ptr _this = this;
m_map = sm;
auto worker = spawn<detached_and_hidden>([_this, sm] {
auto worker = spawn<hidden>([_this, sm] {
typedef map<string, pair<actor_ptr, vector<pair<string, remote_group_ptr>>>>
peer_map;
peer_map peers;
......@@ -529,7 +529,7 @@ local_group::local_group(bool spawn_local_broker,
local_group_module* mod,
string id)
: group(mod, move(id)) {
if (spawn_local_broker) m_broker = spawn_hidden<local_broker>(this);
if (spawn_local_broker) m_broker = spawn<local_broker, hidden>(this);
}
void local_group::serialize(serializer* sink) {
......
......@@ -28,8 +28,12 @@
\******************************************************************************/
#include "cppa/on.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/memory.hpp"
namespace cppa {
......
......@@ -41,6 +41,7 @@
#include "cppa/scheduler.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/detail/actor_count.hpp"
#include "cppa/detail/singleton_manager.hpp"
......@@ -108,7 +109,7 @@ class delayed_msg {
private:
either<async_send_fun, sync_reply_fun> fun;
either<async_send_fun,sync_reply_fun> fun;
channel_ptr ptr_a;
actor_ptr ptr_b;
......@@ -347,5 +348,4 @@ const actor_ptr& scheduler::printer() const {
return m_helper->m_printer;
}
} // namespace cppa
This diff is collapsed.
......@@ -157,7 +157,7 @@ int client_part(const vector<string_pair>& args) {
send(server, atom("SpawnPing"));
receive (
on(atom("PingPtr"), arg_match) >> [](actor_ptr ping_actor) {
spawn<detached>(pong, ping_actor);
spawn<detached + blocking_api>(pong, ping_actor);
}
);
await_all_others_done();
......
......@@ -121,10 +121,10 @@ class testee_actor {
void wait4string() {
bool string_received = false;
do_receive (
on<string>() >> [&]() {
on<string>() >> [&] {
string_received = true;
},
on<atom("get_state")>() >> [&]() {
on<atom("get_state")>() >> [&] {
reply("wait4string");
}
)
......@@ -134,10 +134,10 @@ class testee_actor {
void wait4float() {
bool float_received = false;
do_receive (
on<float>() >> [&]() {
on<float>() >> [&] {
float_received = true;
},
on<atom("get_state")>() >> [&]() {
on<atom("get_state")>() >> [&] {
reply("wait4float");
}
)
......@@ -149,10 +149,10 @@ class testee_actor {
void operator()() {
receive_loop (
on<int>() >> [&]() {
on<int>() >> [&] {
wait4float();
},
on<atom("get_state")>() >> [&]() {
on<atom("get_state")>() >> [&] {
reply("wait4int");
}
);
......@@ -162,33 +162,19 @@ class testee_actor {
// receives one timeout and quits
void testee1() {
receive (
after(chrono::milliseconds(10)) >> []() { }
);
become(after(chrono::milliseconds(10)) >> [] { unbecome(); });
}
void testee2(actor_ptr other) {
self->link_to(other);
send(other, uint32_t(1));
receive_loop (
become (
on<uint32_t>() >> [](uint32_t sleep_time) {
// "sleep" for sleep_time milliseconds
receive(after(chrono::milliseconds(sleep_time)) >> []() {});
//reply(sleep_time * 2);
}
);
}
void testee3(actor_ptr parent) {
// test a delayed_send / delayed_reply based loop
delayed_send(self, chrono::milliseconds(50), atom("Poll"));
int polls = 0;
receive_for(polls, 5) (
on(atom("Poll")) >> [&]() {
if (polls < 4) {
delayed_reply(chrono::milliseconds(50), atom("Poll"));
}
send(parent, atom("Push"), polls);
become (
keep_behavior,
after(chrono::milliseconds(sleep_time)) >> [] { unbecome(); }
);
}
);
}
......@@ -277,9 +263,10 @@ class fixed_stack : public sb_actor<fixed_stack> {
};
void echo_actor() {
receive (
others() >> []() {
become (
others() >> [] {
reply_tuple(self->last_dequeued());
self->quit(exit_reason::normal);
}
);
}
......@@ -423,7 +410,7 @@ int main() {
await_all_others_done();
CPPA_CHECKPOINT();
auto sync_testee1 = spawn([]() {
auto sync_testee1 = spawn<blocking_api>([] {
receive (
on(atom("get")) >> []() {
reply(42, 2);
......@@ -629,27 +616,23 @@ int main() {
}).spawn();
await_all_others_done();
auto res1 = behavior_test<testee_actor>(spawn(testee_actor{}));
auto res1 = behavior_test<testee_actor>(spawn<blocking_api>(testee_actor{}));
CPPA_CHECK_EQUAL("wait4int", res1);
CPPA_CHECK_EQUAL(behavior_test<event_testee>(spawn<event_testee>()), "wait4int");
// create 20,000 actors linked to one single actor
// and kill them all through killing the link
auto twenty_thousand = spawn([]() {
auto twenty_thousand = spawn([] {
for (int i = 0; i < 20000; ++i) {
spawn_link<event_testee>();
spawn<event_testee, linked>();
}
receive_loop (
others() >> []() {
cout << "wtf? => " << to_string(self->last_dequeued()) << endl;
}
);
become(others() >> CPPA_UNEXPECTED_MSG_CB());
});
quit_actor(twenty_thousand, exit_reason::user_defined);
await_all_others_done();
self->trap_exit(true);
auto ping_actor = spawn_monitor(ping, 10);
auto pong_actor = spawn_monitor(pong, ping_actor);
auto ping_actor = spawn<monitored + blocking_api>(ping, 10);
auto pong_actor = spawn<monitored + blocking_api>(pong, ping_actor);
self->link_to(pong_actor);
int i = 0;
int flags = 0;
......
......@@ -171,9 +171,9 @@ int main() {
self->on_sync_failure([] {
CPPA_ERROR("received: " << to_string(self->last_dequeued()));
});
spawn_monitor([&] {
spawn<monitored + blocking_api>([&] {
int invocations = 0;
auto foi = spawn_link<float_or_int>();
auto foi = spawn<float_or_int, linked>();
send(foi, atom("i"));
receive(on_arg_match >> [](int i) { CPPA_CHECK_EQUAL(i, 0); });
self->on_sync_failure([] {
......@@ -228,11 +228,11 @@ int main() {
}
);
};
send(spawn_monitor<A>(self), atom("go"), spawn<B>(spawn<C>()));
send(spawn<A, monitored>(self), atom("go"), spawn<B>(spawn<C>()));
await_success_message();
CPPA_CHECKPOINT();
await_all_others_done();
send(spawn_monitor<A>(self), atom("go"), spawn<D>(spawn<C>()));
send(spawn<A, monitored>(self), atom("go"), spawn<D>(spawn<C>()));
await_success_message();
CPPA_CHECKPOINT();
await_all_others_done();
......@@ -276,10 +276,10 @@ int main() {
CPPA_CHECKPOINT();
// test use case 3
spawn_monitor([] { // client
auto s = spawn_link<server>(); // server
auto w = spawn_link([] { // worker
receive_loop(on(atom("request")) >> []{ reply(atom("response")); });
spawn<monitored>([] { // client
auto s = spawn<server, linked>(); // server
auto w = spawn<linked>([] { // worker
become(on(atom("request")) >> []{ reply(atom("response")); });
});
// first 'idle', then 'request'
send_as(w, s, atom("idle"));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment