Hi,
My name is Paul and I'm with the LSI (Interactive Simulation Lab), of the
French CEA.
We've started playing with Orocos in my lab and some PhD students working in
robot control complained about their simulations not being reproductible. I
quickly figured that the problem was that the physical simulation and the
control component (both of them are RTT::TaskContext) were running in
separate threads.
I tried synchronizing them by assigning PeriodicActivities with the same
priority and period.This works fine, except when one component tries calling
operations provided by the other one: since all operations are tagged with
RTT::OwnThread, we got deadlocks.
I don't really want to provide two versions of each operation since such a
solution would make the client code dependent on whether the components are
synchronized or not. I found a workaround which consists in giving the
callee's execution engine to the OperationCaller when the caller's and
callee's activities run in the same thread. I'm not sure what it's worth...
After looking into the source code, I ran into this in
LocalOperationCaller.hpp :
result_type call_impl()
{
if (met == OwnThread && myengine != caller) {
SendHandle<Signature> h = send_impl();
if ( h.collect() == SendSuccess )
return h.ret();
else
throw SendFailure;
} else {
if (this->msig) this->msig->emit();
if ( this->mmeth )
return this->mmeth(); // ClientThread
else
return NA<result_type>::na();
}
}
So I believe that indeed when I give the callee's execution engine to the
caller, we fall into the top-level else{} and run the same code as when the
operation is tagged with ClientThread.
Isn't it dangerous to call h.collect() when met == OwnThread && myengine !=
caller AND myengine->getThread()->isSelf()? It leads to
ExecutionEngine::waitAndProcessMessages where I get stuck when the caller's
and callee's engines share the same thread.
Would it be suitable to change
if (met == OwnThread && myengine != caller) {
with
if (met == OwnThread && myengine != caller &&
!myengine->getThread()->isSelf()) { // btw, can myengine be null?
?
Below is some c++ code to illustrate the issue.
Thanks in advance.
Deadlocks with RTT::OwnThread and PeriodicActivity
On 12 Apr 2011, at 11:46, Paul Evrard wrote:
Hi,
My name is Paul and I'm with the LSI (Interactive Simulation Lab), of the French CEA.
We've started playing with Orocos in my lab and some PhD students working in robot control complained about their simulations not being reproductible. I quickly figured that the problem was that the physical simulation and the control component (both of them are RTT::TaskContext) were running in separate threads.
I tried synchronizing them by assigning PeriodicActivities with the same priority and period.This works fine, except when one component tries calling operations provided by the other one: since all operations are tagged with RTT::OwnThread, we got deadlocks.
Are you using RTT 1.x or 2.x?
When you want to explicitly synchronize two different components I suggest you take a look at the Master/Slave-Activities. Since these are explicitly designed for synchronization. I don't know whether that would solve your problem though.
-- Ruben
I don't really want to provide two versions of each operation since such a solution would make the client code dependent on whether the components are synchronized or not. I found a workaround which consists in giving the callee's execution engine to the OperationCaller when the caller's and callee's activities run in the same thread. I'm not sure what it's worth...
After looking into the source code, I ran into this in LocalOperationCaller.hpp :
result_type call_impl()
{
if (met == OwnThread && myengine != caller) {
SendHandle<Signature> h = send_impl();
if ( h.collect() == SendSuccess )
return h.ret();
else
throw SendFailure;
} else {
if (this->msig) this->msig->emit();
if ( this->mmeth )
return this->mmeth(); // ClientThread
else
return NA<result_type>::na();
}
}
So I believe that indeed when I give the callee's execution engine to the caller, we fall into the top-level else{} and run the same code as when the operation is tagged with ClientThread.
Isn't it dangerous to call h.collect() when met == OwnThread && myengine != caller AND myengine->getThread()->isSelf()? It leads to ExecutionEngine::waitAndProcessMessages where I get stuck when the caller's and callee's engines share the same thread.
Would it be suitable to change
if (met == OwnThread && myengine != caller) {
with
if (met == OwnThread && myengine != caller && !myengine->getThread()->isSelf()) { // btw, can myengine be null?
?
Below is some c++ code to illustrate the issue.
Thanks in advance.
--
Paul
#pragma warning(disable : 4244 4251 4267 4355 4985)
#include <rtt/TaskContext.hp
#include <rtt/extras/PeriodicActivity.
hp
#include <rtt/OperationCaller.hp
#pragma warning(default : 4244 4251 4267 4355 4985)
#include <boost/lexical_cast.hp
#include <iostream>
// ------------------------------------------------------------
// --- AGENT BASE ---------------------------------------------
// ------------------------------------------------------------
class AgentBase
: public RTT::TaskContext
{
public:
static int i;
AgentBase(RTT::base::ActivityInterface* act)
: TaskContext("agent"+boost::lexical_cast<std::string>(i))
{
++i;
this->setActivity(act);
this->getActivity()->thread()->setWaitPeriodPolicy(ORO_WAIT_REL);
}
};
int AgentBase::i = 0;
// ------------------------------------------------------------
// --- AGENT1 -------------------------------------------------
// ------------------------------------------------------------
class Agent1
: public AgentBase
{
public:
Agent1()
: AgentBase(new RTT::extras::PeriodicActivity(0, .001))
{
this->addOperation("toto", &Agent1::toto, this, RTT::OwnThread);
}
void toto()
{
std::cout << "Agent1::toto, agent1 thread: " << getActivity()->thread()->isSelf() << " agent2 thread: " << copain->getActivity()->thread()->isSelf() << std::endl;
}
void updateHook()
{
std::cout << "Enter and leave Update AGENT 1" << std::endl;
copain->trigger();
}
AgentBase* copain;
};
// ------------------------------------------------------------
// --- AGENT2 -------------------------------------------------
// ------------------------------------------------------------
class Agent2
: public AgentBase
{
public:
Agent2(Agent1& copain)
: AgentBase(new RTT::extras::PeriodicActivity(0, .001))
, copain_(copain)
{
}
void updateHook()
{
std::cout << "Enter Update AGENT 2" << std::endl;
// The goal here is to call the operation toto provided by Agent1's instance.
// For some reasons (we are playing with stubbers and that kind of stuff), I
// would like to always use the operator() on the OperationCaller's instance,
// and never use send.
// The ideal solution would be that depending on whether Agent1's and Agent2's
// updatehooks run in the same thread or not, the operation will behave as
// if tagged as ClientThread or OwnThread.
// The following lines deadlocks if both agents are running in the same thread and runs fine otherwise.
//RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"));
//toto();
// With the following lines, toto() is called after leaving this update hook, which is the
// expected behavior for an operation (that's why call() creates a deadlock when activities share the same thread).
// However, it means that operations that can be used are those not returning values...
//RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
//if(engine()->getThread() == copain_.engine()->getThread())
// toto.send();
//else
// toto();
// The following lines are a hack to avoid blocking when both agents are running in the same thread...
// It sorts of calls the operation as if it had been tagged with RTT::ClientThread.
// It solves our problem, but is it an expected behavior, or is it just a workaround that can
// die with future updates?
RTT::ExecutionEngine* ee = (engine()->getThread() == copain_.engine()->getThread()) ? copain_.engine() : 0x0;
RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
toto();
std::cout << "Leave Update AGENT 2" << std::endl;
}
private:
Agent1& copain_;
};
// ------------------------------------------------------------
// --- MAIN ---------------------------------------------------
// ------------------------------------------------------------
int main()
{
Agent1 agent1;
Agent2 agent2(agent1);
agent1.copain = &agent2;
agent1.start();
agent2.start();
int coin;
while(true)
std::cin >> coin;
}
--
Paul
<ATT00001..txt>
Deadlocks with RTT::OwnThread and PeriodicActivity
On Tue, Apr 12, 2011 at 4:37 PM, Ruben Smits
<Ruben [dot] Smits [..] ...> wrote:
>
> On 12 Apr 2011, at 11:46, Paul Evrard wrote:
> Are you using RTT 1.x or 2.x?
Hi,
I'm using RTT 2.1 on a win32 platform.
> When you want to explicitly synchronize two different components I suggest
> you take a look at the Master/Slave-Activities. Since these are explicitly
> designed for synchronization. I don't know whether that would solve your
> problem though.
Yes, that might solve my problem, I will test it. I have to be sure
that there is no overlap between the updateHook of the control task
and the one of the physical simulation task.
However, I think that the issue I pointed out with PeriodicActivity
should be tackled. It seems dangerous to have a behavior such that
depending on what priority you set to your PeriodicActivities, you
might or might not get deadlocks when calling RTT::OwnThread-tagged
operations.
Deadlocks with RTT::OwnThread and PeriodicActivity
On 12 Apr 2011, at 11:46, Paul Evrard wrote:
Hi,
My name is Paul and I'm with the LSI (Interactive Simulation Lab), of the French CEA.
We've started playing with Orocos in my lab and some PhD students working in robot control complained about their simulations not being reproductible. I quickly figured that the problem was that the physical simulation and the control component (both of them are RTT::TaskContext) were running in separate threads.
I tried synchronizing them by assigning PeriodicActivities with the same priority and period.This works fine, except when one component tries calling operations provided by the other one: since all operations are tagged with RTT::OwnThread, we got deadlocks.
Are you using RTT 1.x or 2.x?
When you want to explicitly synchronize two different components I suggest you take a look at the Master/Slave-Activities. Since these are explicitly designed for synchronization. I don't know whether that would solve your problem though.
-- Ruben
I don't really want to provide two versions of each operation since such a solution would make the client code dependent on whether the components are synchronized or not. I found a workaround which consists in giving the callee's execution engine to the OperationCaller when the caller's and callee's activities run in the same thread. I'm not sure what it's worth...
After looking into the source code, I ran into this in LocalOperationCaller.hpp :
result_type call_impl()
{
if (met == OwnThread && myengine != caller) {
SendHandle<Signature> h = send_impl();
if ( h.collect() == SendSuccess )
return h.ret();
else
throw SendFailure;
} else {
if (this->msig) this->msig->emit();
if ( this->mmeth )
return this->mmeth(); // ClientThread
else
return NA<result_type>::na();
}
}
So I believe that indeed when I give the callee's execution engine to the caller, we fall into the top-level else{} and run the same code as when the operation is tagged with ClientThread.
Isn't it dangerous to call h.collect() when met == OwnThread && myengine != caller AND myengine->getThread()->isSelf()? It leads to ExecutionEngine::waitAndProcessMessages where I get stuck when the caller's and callee's engines share the same thread.
Would it be suitable to change
if (met == OwnThread && myengine != caller) {
with
if (met == OwnThread && myengine != caller && !myengine->getThread()->isSelf()) { // btw, can myengine be null?
?
Below is some c++ code to illustrate the issue.
Thanks in advance.
--
Paul
#pragma warning(disable : 4244 4251 4267 4355 4985)
#include <rtt/TaskContext.hp
#include <rtt/extras/PeriodicActivity.
hp
#include <rtt/OperationCaller.hp
#pragma warning(default : 4244 4251 4267 4355 4985)
#include <boost/lexical_cast.hp
#include <iostream>
// ------------------------------------------------------------
// --- AGENT BASE ---------------------------------------------
// ------------------------------------------------------------
class AgentBase
: public RTT::TaskContext
{
public:
static int i;
AgentBase(RTT::base::ActivityInterface* act)
: TaskContext("agent"+boost::lexical_cast<std::string>(i))
{
++i;
this->setActivity(act);
this->getActivity()->thread()->setWaitPeriodPolicy(ORO_WAIT_REL);
}
};
int AgentBase::i = 0;
// ------------------------------------------------------------
// --- AGENT1 -------------------------------------------------
// ------------------------------------------------------------
class Agent1
: public AgentBase
{
public:
Agent1()
: AgentBase(new RTT::extras::PeriodicActivity(0, .001))
{
this->addOperation("toto", &Agent1::toto, this, RTT::OwnThread);
}
void toto()
{
std::cout << "Agent1::toto, agent1 thread: " << getActivity()->thread()->isSelf() << " agent2 thread: " << copain->getActivity()->thread()->isSelf() << std::endl;
}
void updateHook()
{
std::cout << "Enter and leave Update AGENT 1" << std::endl;
copain->trigger();
}
AgentBase* copain;
};
// ------------------------------------------------------------
// --- AGENT2 -------------------------------------------------
// ------------------------------------------------------------
class Agent2
: public AgentBase
{
public:
Agent2(Agent1& copain)
: AgentBase(new RTT::extras::PeriodicActivity(0, .001))
, copain_(copain)
{
}
void updateHook()
{
std::cout << "Enter Update AGENT 2" << std::endl;
// The goal here is to call the operation toto provided by Agent1's instance.
// For some reasons (we are playing with stubbers and that kind of stuff), I
// would like to always use the operator() on the OperationCaller's instance,
// and never use send.
// The ideal solution would be that depending on whether Agent1's and Agent2's
// updatehooks run in the same thread or not, the operation will behave as
// if tagged as ClientThread or OwnThread.
// The following lines deadlocks if both agents are running in the same thread and runs fine otherwise.
//RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"));
//toto();
// With the following lines, toto() is called after leaving this update hook, which is the
// expected behavior for an operation (that's why call() creates a deadlock when activities share the same thread).
// However, it means that operations that can be used are those not returning values...
//RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
//if(engine()->getThread() == copain_.engine()->getThread())
// toto.send();
//else
// toto();
// The following lines are a hack to avoid blocking when both agents are running in the same thread...
// It sorts of calls the operation as if it had been tagged with RTT::ClientThread.
// It solves our problem, but is it an expected behavior, or is it just a workaround that can
// die with future updates?
RTT::ExecutionEngine* ee = (engine()->getThread() == copain_.engine()->getThread()) ? copain_.engine() : 0x0;
RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
toto();
std::cout << "Leave Update AGENT 2" << std::endl;
}
private:
Agent1& copain_;
};
// ------------------------------------------------------------
// --- MAIN ---------------------------------------------------
// ------------------------------------------------------------
int main()
{
Agent1 agent1;
Agent2 agent2(agent1);
agent1.copain = &agent2;
agent1.start();
agent2.start();
int coin;
while(true)
std::cin >> coin;
}
--
Paul
<ATT00001..txt>
Deadlocks with RTT::OwnThread and PeriodicActivity
Hi,
My name is Paul and I'm with the LSI (Interactive Simulation Lab), of
the French CEA.
We've started playing with Orocos in my lab and some PhD students
working in robot control complained about their simulations not being
reproductible. I quickly figured that the problem was that the
physical simulation and the control component (both of them are
RTT::TaskContext) were running in separate threads.
I tried synchronizing them by assigning PeriodicActivities with the
same priority and period.This works fine, except when one component
tries calling operations provided by the other one: since all
operations are tagged with RTT::OwnThread, we got deadlocks.
I don't really want to provide two versions of each operation since
such a solution would make the client code dependent on whether the
components are synchronized or not. I found a workaround which
consists in giving the callee's execution engine to the
OperationCaller when the caller's and callee's activities run in the
same thread. I'm not sure what it's worth...
After looking into the source code, I ran into this in
LocalOperationCaller.hpp :
result_type call_impl()
{
if (met == OwnThread && myengine != caller) {
SendHandle<Signature> h = send_impl();
if ( h.collect() == SendSuccess )
return h.ret();
else
throw SendFailure;
} else {
if (this->msig) this->msig->emit();
if ( this->mmeth )
return this->mmeth(); // ClientThread
else
return NA<result_type>::na();
}
}
So I believe that indeed when I give the callee's execution engine to
the caller, we fall into the top-level else{} and run the same code as
when the operation is tagged with ClientThread.
Isn't it dangerous to call h.collect() when met == OwnThread &&
myengine != caller AND myengine->getThread()->isSelf(
)? It leads to ExecutionEngine::waitAndProcessMessages where I get
stuck when the caller's and callee's engines share the same thread.
Would it be suitable to change
if (met == OwnThread && myengine != caller) {
with
if (met == OwnThread && myengine != caller &&
!myengine->getThread()->isSelf()) { // btw, can myengine be null?
?
Below is some c++ code to illustrate the issue.
Thanks in advance.
--
Paul
#pragma warning(disable : 4244 4251 4267 4355 4985)
#include <rtt/TaskContext.hp
#include <rtt/extras/PeriodicActivity.
hp
#include <rtt/OperationCaller.hp
#pragma warning(default : 4244 4251 4267 4355 4985)
#include <boost/lexical_cast.hp
#include <iostream>
// ------------------------------------------------------------
// --- AGENT BASE ---------------------------------------------
// ------------------------------------------------------------
class AgentBase
: public RTT::TaskContext
{
public:
static int i;
AgentBase(RTT::base::ActivityInterface* act)
: TaskContext("agent"+boost::lexical_cast<std::string>(i))
{
++i;
this->setActivity(act);
this->getActivity()->thread()->setWaitPeriodPolicy(ORO_WAIT_REL);
}
};
int AgentBase::i = 0;
// ------------------------------------------------------------
// --- AGENT1 -------------------------------------------------
// ------------------------------------------------------------
class Agent1
: public AgentBase
{
public:
Agent1()
: AgentBase(new RTT::extras::PeriodicActivity(0, .001))
{
this->addOperation("toto", &Agent1::toto, this, RTT::OwnThread);
}
void toto()
{
std::cout << "Agent1::toto, agent1 thread: " <<
getActivity()->thread()->isSelf() << " agent2 thread: " <<
copain->getActivity()->thread()->isSelf() << std::endl;
}
void updateHook()
{
std::cout << "Enter and leave Update AGENT 1" << std::endl;
copain->trigger();
}
AgentBase* copain;
};
// ------------------------------------------------------------
// --- AGENT2 -------------------------------------------------
// ------------------------------------------------------------
class Agent2
: public AgentBase
{
public:
Agent2(Agent1& copain)
: AgentBase(new RTT::extras::PeriodicActivity(0, .001))
, copain_(copain)
{
}
void updateHook()
{
std::cout << "Enter Update AGENT 2" << std::endl;
// The goal here is to call the operation toto provided by
Agent1's instance.
// For some reasons (we are playing with stubbers and that kind of stuff), I
// would like to always use the operator() on the
OperationCaller's instance,
// and never use send.
// The ideal solution would be that depending on whether Agent1's
and Agent2's
// updatehooks run in the same thread or not, the operation will behave as
// if tagged as ClientThread or OwnThread.
// The following lines deadlocks if both agents are running in the
same thread and runs fine otherwise.
//RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"));
//toto();
// With the following lines, toto() is called after leaving this
update hook, which is the
// expected behavior for an operation (that's why call() creates a
deadlock when activities share the same thread).
// However, it means that operations that can be used are those
not returning values...
//RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
//if(engine()->getThread() == copain_.engine()->getThread())
// toto.send();
//else
// toto();
// The following lines are a hack to avoid blocking when both
agents are running in the same thread...
// It sorts of calls the operation as if it had been tagged with
RTT::ClientThread.
// It solves our problem, but is it an expected behavior, or is it
just a workaround that can
// die with future updates?
RTT::ExecutionEngine* ee = (engine()->getThread() ==
copain_.engine()->getThread()) ? copain_.engine() : 0x0;
RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
toto();
std::cout << "Leave Update AGENT 2" << std::endl;
}
private:
Agent1& copain_;
};
// ------------------------------------------------------------
// --- MAIN ---------------------------------------------------
// ------------------------------------------------------------
int main()
{
Agent1 agent1;
Agent2 agent2(agent1);
agent1.copain = &agent2;
agent1.start();
agent2.start();
int coin;
while(true)
std::cin >> coin;
}
--
Paul
--
Orocos-Dev mailing list
Orocos-Dev [..] ...
http://lists.mech.kuleuven.be/mailman/listinfo/orocos-dev
Deadlocks with RTT::OwnThread and PeriodicActivity
On Tue, 12 Apr 2011, Paul Evrard wrote:
> My name is Paul and I'm with the LSI (Interactive Simulation Lab), of
> the French CEA.
Nice to make your acquaintance, albeit only electronically :-)
> We've started playing with Orocos in my lab and some PhD students
> working in robot control complained about their simulations not being
> reproductible. I quickly figured that the problem was that the
> physical simulation and the control component (both of them are
> RTT::TaskContext) were running in separate threads.
>
> I tried synchronizing them by assigning PeriodicActivities with the
> same priority and period.This works fine, except when one component
> tries calling operations provided by the other one: since all
> operations are tagged with RTT::OwnThread, we got deadlocks.
Of course...
> I don't really want to provide two versions of each operation since
> such a solution would make the client code dependent on whether the
> components are synchronized or not. I found a workaround which
> consists in giving the callee's execution engine to the
> OperationCaller when the caller's and callee's activities run in the
> same thread. I'm not sure what it's worth...
Nothing, frankly speaking.
This kind of application (multi-threading or multi-process or
multi-CPU or multi-computer simulations) require the following well known
pattern to succeed. (If you are interested in an implementation framework,
you could take a look at CERTI <http://savannah.nongnu.org/projects/certi>).
The design is based on the "mediator pattern", which in your case means
that you introduce on "simulation coordination component", which is peer of
the simulation threads, which triggers them when they have to execute one
(or more) steps in their simulation and return the result. In other words,
instead of having _one_ of the different simulation threads coordinate the
others, you have to let a third independent party do that job. That
mediator is the only place where the information about all participating
simulation components needs to be known and used; it also decouples the
interactions between the simulation components. Yes, it introduces some
coordination overhead, but it is the only way that can _prevent_ deadlocks,
and _guarantee_ "ideal, deterministic" synchronisation.
Herman
> After looking into the source code, I ran into this in
> LocalOperationCaller.hpp :
>
> result_type call_impl()
> {
>
> if (met == OwnThread && myengine != caller) {
> SendHandle<Signature> h = send_impl();
> if ( h.collect() == SendSuccess )
> return h.ret();
> else
> throw SendFailure;
> } else {
> if (this->msig) this->msig->emit();
> if ( this->mmeth )
> return this->mmeth(); // ClientThread
> else
> return NA<result_type>::na();
> }
> }
>
> So I believe that indeed when I give the callee's execution engine to
> the caller, we fall into the top-level else{} and run the same code as
> when the operation is tagged with ClientThread.
>
> Isn't it dangerous to call h.collect() when met == OwnThread &&
> myengine != caller AND myengine->getThread()->isSelf(
> )? It leads to ExecutionEngine::waitAndProcessMessages where I get
> stuck when the caller's and callee's engines share the same thread.
>
> Would it be suitable to change
> if (met == OwnThread && myengine != caller) {
>
> with
> if (met == OwnThread && myengine != caller &&
> !myengine->getThread()->isSelf()) { // btw, can myengine be null?
> ?
>
> Below is some c++ code to illustrate the issue.
>
> Thanks in advance.
> --
> Paul
>
> #pragma warning(disable : 4244 4251 4267 4355 4985)
> #include <rtt/TaskContext.hp
> #include <rtt/extras/PeriodicActivity.
> hpp>
> #include <rtt/OperationCaller.hp
> #pragma warning(default : 4244 4251 4267 4355 4985)
>
> #include <boost/lexical_cast.hp
> #include <iostream>
>
>
> // ------------------------------------------------------------
> // --- AGENT BASE ---------------------------------------------
> // ------------------------------------------------------------
>
> class AgentBase
> : public RTT::TaskContext
> {
> public:
> static int i;
>
> AgentBase(RTT::base::ActivityInterface* act)
> : TaskContext("agent"+boost::lexical_cast<std::string>(i))
> {
> ++i;
> this->setActivity(act);
> this->getActivity()->thread()->setWaitPeriodPolicy(ORO_WAIT_REL);
> }
> };
>
> int AgentBase::i = 0;
>
>
> // ------------------------------------------------------------
> // --- AGENT1 -------------------------------------------------
> // ------------------------------------------------------------
>
> class Agent1
> : public AgentBase
> {
> public:
> Agent1()
> : AgentBase(new RTT::extras::PeriodicActivity(0, .001))
> {
> this->addOperation("toto", &Agent1::toto, this, RTT::OwnThread);
> }
>
> void toto()
> {
> std::cout << "Agent1::toto, agent1 thread: " <<
> getActivity()->thread()->isSelf() << " agent2 thread: " <<
> copain->getActivity()->thread()->isSelf() << std::endl;
> }
>
> void updateHook()
> {
> std::cout << "Enter and leave Update AGENT 1" << std::endl;
> copain->trigger();
> }
>
> AgentBase* copain;
> };
>
>
> // ------------------------------------------------------------
> // --- AGENT2 -------------------------------------------------
> // ------------------------------------------------------------
>
> class Agent2
> : public AgentBase
> {
> public:
> Agent2(Agent1& copain)
> : AgentBase(new RTT::extras::PeriodicActivity(0, .001))
> , copain_(copain)
> {
> }
>
> void updateHook()
> {
> std::cout << "Enter Update AGENT 2" << std::endl;
>
> // The goal here is to call the operation toto provided by
> Agent1's instance.
> // For some reasons (we are playing with stubbers and that kind of stuff), I
> // would like to always use the operator() on the
> OperationCaller's instance,
> // and never use send.
> // The ideal solution would be that depending on whether Agent1's
> and Agent2's
> // updatehooks run in the same thread or not, the operation will behave as
> // if tagged as ClientThread or OwnThread.
>
> // The following lines deadlocks if both agents are running in the
> same thread and runs fine otherwise.
> //RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"));
> //toto();
>
> // With the following lines, toto() is called after leaving this
> update hook, which is the
> // expected behavior for an operation (that's why call() creates a
> deadlock when activities share the same thread).
> // However, it means that operations that can be used are those
> not returning values...
> //RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
> //if(engine()->getThread() == copain_.engine()->getThread())
> // toto.send();
> //else
> // toto();
>
> // The following lines are a hack to avoid blocking when both
> agents are running in the same thread...
> // It sorts of calls the operation as if it had been tagged with
> RTT::ClientThread.
> // It solves our problem, but is it an expected behavior, or is it
> just a workaround that can
> // die with future updates?
> RTT::ExecutionEngine* ee = (engine()->getThread() ==
> copain_.engine()->getThread()) ? copain_.engine() : 0x0;
> RTT::OperationCaller<void(void)> toto(copain_.getOperation("toto"), ee);
> toto();
>
> std::cout << "Leave Update AGENT 2" << std::endl;
> }
> private:
> Agent1& copain_;
> };
>
>
> // ------------------------------------------------------------
> // --- MAIN ---------------------------------------------------
> // ------------------------------------------------------------
>
> int main()
> {
> Agent1 agent1;
> Agent2 agent2(agent1);
> agent1.copain = &agent2;
>
> agent1.start();
> agent2.start();
>
> int coin;
> while(true)
> std::cin >> coin;
> }
> --
> Paul