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