Open randaz81 opened 10 years ago
Thank you for the suggestions, I'll add these features.
I've got a couple of questions about the code you posted:
1) return false; //note also this
In this case, what exactly happens when false is returned? The documentation (http://eris.liralab.it/yarpdoc/classyarp_1_1os_1_1RFModule.html#a0e86b0f6df2e533aa8ae87fbfd4491df) says "Returns: true if there was no critical failure ". I have run the program and seen that interruptModule() and then close() are called in sequence. Am I right? Is there anything else RFModule does in this circumstance?
2) Thread->mutex.post(); //remember the unlock your mutex(s)!
Why should the mutex be unlocked here? I am protecting the access to the actionL, actionR objects. Thus, I place a protected area in each case of the respond() method where actionL, actionR are accessed (e.g. open_left_hand, as reported below).
if (receivedCmd == "open_left_hand")
{
actionMutex.lock(); //Protected area beginning
// Stop current motion and clear actions queue
actionL->stopControl();
actionR->stopControl();
[...]
actionMutex.unlock(); //Protected area ending
}
However, in the "quit" case I neither access actionL, nor actionR, so I wonder why the mutex should be unlocked.
Thanks.
1) yes, returning false has the effect you reversed-ingeneered. Documentation is missing. :-) If your RFmodule opened additional threads, always remeber to stop them in the interruptModule() or close().
2) your code changed a bit and I cannot find anymore your actionMutex.unlock(). Maybe I'm wrong, but if I remember correctly the previous version, I noticed ad possibile deadlock if the execution flow was stopped by the mutex inside updateModule() and the return false statement in the respond() was reached without releasing the mutex. My suspect is that in this case it is impossibile to complete the execution of updateModule(), and therefore interruptModule() is not called (or maybe it is called, but the module cannot close because updateModule() is still blocked)
2014-05-20 12:42 GMT+02:00 Raffaello Camoriano notifications@github.com:
I've got a couple of questions about the code you posted:
1) return false; //note also this
In this case, what exactly happens when false is returned? The documentation ( http://eris.liralab.it/yarpdoc/classyarp_1_1os_1_1RFModule.html#a0e86b0f6df2e533aa8ae87fbfd4491df) says "Returns: true if there was no critical failure ". I have run the program and seen that interruptModule() and then close() are called in sequence. Am I right? Is there anything else RFModule does in this circumstance?
1) Thread->mutex.post(); //remember the unlock your mutex(s)!
Why should the mutex be unlocked here? I am protecting the access to the actionL, actionR objects. Thus, I place a protected area in each case of the respond() method where actionL, actionR are accessed (e.g. open_left_hand, as reported below).
if (receivedCmd == "open_left_hand") { actionMutex.lock(); //Protected area beginning
// Stop current motion and clear actions queue actionL->stopControl(); actionR->stopControl(); [...] actionMutex.unlock(); //Protected area ending }
However, in the "quit" case I neither access actionL, nor actionR, so I wonder why the mutex should be unlocked.
Thanks.
— Reply to this email directly or view it on GitHubhttps://github.com/Ommac/RBDemo/issues/24#issuecomment-43610360 .
I have analysed the different cases, considering the updateModule(), respond(), interruptModule() and close() flows and the calls to blocking and unblocking functions therein contained, in the case in which a "quit" command is received via rpc at any moment.
Below is the analysis in pseudocode.
Functions flows
updateModule() while(shouldRun) { read port // Blocked state (1) [...] lock mutex // Blocked state (2) [...] access actions waitActionsDone // Blocked state (3) [...] unlock mutex [...] wait 0.1 seconds }
respond() unlock mutex return false //interruptModule is then called
interruptModule syncCheckInterrput // Unlocks waitActionsDone interrupt all ports // close() is then called
close() deallocate actions close all ports stop module
Shutdown cases
Here I'll report the 3 cases I identified for module shutdown via rpc, namely receiving a "quit" command at any moment. I have considered what happens as the "quit" command is received in correspondance with the blocked states 1, 2 and 3 within updateModule.
Case 1 UpdateModule blocked on the port to be read.
respond(), interruptModule() and close()
Case 2 UpdateModule blocked by the mutex.
respond(), interruptModule() and close()
Case 3 UpdateModule blocked by waitActionsDone.
respond(), interruptModule() and close()
A possible neater solution might be:
respond() return false //Note: no other functions are called here //interruptModule is then called
interruptModule interrupt all ports unlock mutex syncCheckInterrput // Unlocks waitActionsDone // close() is then called
close() deallocate actions close all ports stop module
All the unblocking functions are called in interruptModule() and close(), so that they operate properly also in the Ctrl-C case, not only when "quit" is received via rpc.
excellent analysis
2014-05-21 10:37 GMT+02:00 Raffaello Camoriano notifications@github.com:
I have analysed the different cases, considering the updateModule(), respond(), interruptModule() and close() flows and the calls to blocking and unblocking functions therein contained, in the case in which a "quit" command is received via rpc at any moment.
Below is the analysis in pseudocode.
Functions flows
updateModule() while(shouldRun) { read port // Blocked state (1) [...] lock mutex // Blocked state (2) [...] access actions waitActionsDone // Blocked state (3) [...] unlock mutex [...] wait 0.1 seconds }
respond() unlock mutex return false //interruptModule is then called
interruptModule syncCheckInterrput // Unlocks waitActionsDone interrupt all ports // close() is then called
close() deallocate actions close all ports
stop module
Shutdown cases
Here I'll report the 3 cases I identified for module shutdown via rpc, namely receiving a "quit" command at any moment. I have considered what happens as the "quit" command is received in correspondance with the blocked states 1, 2 and 3 within updateModule.
Case 1 UpdateModule blocked on the port to be read.
respond(), interruptModule() and close()
- unlocks the mutex
- frees waitActions
- interrupts the ports: effect --> updateModule locks the mutex and enters the protected area, operates on the actions objects, exits the protected area and waits 0.1 seconds
- close() is called, the module is closed
Case 2 UpdateModule blocked by the mutex.
respond(), interruptModule() and close()
- unlock the mutex: effect --> updateModule enters in the protected area, performs operations on the action objects and then is blocked by the waitActionsDone.
- free waitActions: effect --> updateModule is freed from the waiting state on waitActionsDone, exits the protected area and waits for 0.1 seconds before the next run.
- interrupt the ports: no effect on updateModule
- close() is called: The module should close correctly in this case
Case 3 UpdateModule blocked by waitActionsDone.
respond(), interruptModule() and close()
- unlocks the mutex: no effect on updateModule
- frees waitActions: effect --> updateModule is freed from the waiting state on waitActionsDone, exits the protected area and waits for 0.1 seconds before the next run.
- interrupts the ports: no effect on updateModule
- close(): The module should close correctly in this case
A possible neater solution might be:
respond() return false //Note: no other functions are called here //interruptModule is then called
interruptModule interrupt all ports unlock mutex syncCheckInterrput // Unlocks waitActionsDone // close() is then called
close() deallocate actions close all ports stop module
All the unblocking functions are called in interruptModule() and close(), so that they operate properly also in the Ctrl-C case, not only when "quit" is received via rpc.
— Reply to this email directly or view it on GitHubhttps://github.com/Ommac/RBDemo/issues/24#issuecomment-43728277 .
Ok, I'll use the new solution and test it (as soon as I fix some naughty linking errors due to something I pleasantly ingore).
in respond(): Often it's useful to add an "help" command, in case the user has forgotten the available rpc commands. Consider the following example (taken from ikartgoto\main.cpp)
[...] else if (command.get(0).asString()=="help") { reply.addVocab(Vocab::encode("many")); reply.addString("Available commands are:"); reply.addString("gotoAbs ");
reply.addString("Available commands are:");
reply.addString("gotoAbs ");
reply.addString("gotoRel ");
reply.addString("set linear_tol ");
reply.addString("set linear_ang ");
reply.addString("set max_lin_speed <m/s>");
reply.addString("set max_ang_speed <deg/s>");
reply.addString("set min_lin_speed <m/s>");
reply.addString("set min_ang_speed <deg/s>");
reply.addString("set obstacle_stop");
reply.addString("set obstacle_avoidance");
}
[...]
Note the first line reply.addVocab(Vocab::encode("many")); which ensure proper multiline formatting for the displayed answer. In your specific case I recommend to put the block: actionL->stopControl(); actionR->stopControl(); actionL->clearActionsQueue(); actionR->clearActionsQueue(); inside the individual command tests, even if the code will be repeated. There may exist rpc commands which will not stop the motion and sometimes the number of commands is so long that the developer may forgive the presence of the global part at the beginning. Also, an rpc command like the following is sometimes useful: if (command.get(0).asString()=="quit") { Thread->mutex.post(); //remember the unlock your mutex(s)! return false; //note also this }