Boost signal and thread support. More...
Boost signal and thread support.
Along with providing access to the basic C functions of libplayerc in a C++ fashion, libplayerc++ also provides additional functionality along the lines of signaling and multithreading. The multithreaded ability of libplayerc++ allieves the developer from having to worry about allotting time to handle messaging. It also allows for the PlayerClient to act as a messaging loop for event driven programs. The signaling and multithreading ability of libplayerc++ is built from the Boost c++ libraries. This is relevant because we will be using boost semantincs for connecting the signals to the client. Much of this functionality can best be illustrated through the use of an example:
/* Copyright (c) 2005, Brad Kratochvil, Toby Collett, Brian Gerkey, Andrew Howard, ... All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Player Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <iostream> #include <boost/signal.hpp> #include <boost/bind.hpp> #include <libplayerc++/playerc++.h> // we have a basic command line parser here #include "args.h" // These are our callback functions. // Currently, they all must return void. void cb1() { std::cout << "cb1" << std::endl; } // Callbacks can also be passed parameters void cb2(uint32_t &aI) { std::cout << "cb2 " << ++aI << std::endl; } // we can also have callbacks in objects class TestCb { int mId; public: TestCb(int aId) : mId(aId) {}; // We'll output the ID of the TestCb, so we can see // which object is being called. void Cb() { std::cout << "TestCb " << mId << std::endl; } void Cb(uint32_t aOpt) { std::cout << "TestCb " << mId << " " << aOpt << std::endl; } }; // we'll use this to stop the client void stop_cb(PlayerCc::PlayerClient* c, uint32_t &i) { // after 10 iterations, stop the client if (++i>10) { std::cout << "stop: " << i << std::endl; c->Stop(); } } int main(int argc, char** argv) { parse_args(argc, argv); // it's always good to put the code in a try block // libplayerc++ throws a PlayerError exception when // it runs into trouble try { // let's setup a client // by default PlayerClient uses localhost and 6665 PlayerCc::PlayerClient client(gHostname, gPort); PlayerCc::CameraProxy cp(&client, 0); // Here, we're connecting a signal to a function. // We keep the connection_t so we can later disconnect. PlayerCc::ClientProxy::connection_t conn; conn = cp.ConnectReadSignal(&cb1); // Signals can also be connected without storing the connection_t, // but you can no longer disconnect them. // In order to use a callback with a argument, you need to bind // the argument to the callback. uint32_t count = 0; cp.ConnectReadSignal(boost::bind(&cb2, count)); // here we're connecting a signal to a member function TestCb test1(1), test2(2); // just like functions, member functions can also be bound // with or without arguments cp.ConnectReadSignal(boost::bind(&TestCb::Cb, boost::ref(test1))); cp.ConnectReadSignal(boost::bind(&TestCb::Cb, boost::ref(test2), 1)); // now, we should see some signals each time Read() is called for the // object that receives the data // libplayerc++ has three different ways for handling messages from the // server. The first is by manually calling Read() each time we would // like to process data. std::cout << "Read()" << std::endl; for (uint32_t i=0; i<10; ++i) { client.Read(); // an example of disconnecting a signal if (4==i) cp.DisconnectReadSignal(conn); } // The PlayerClient can also be used as a messaging loop through the use of // a blocking Run() method. The correct way to tell Run() to quit is // through a stop callback. In this case, we only have a single thread, // so we don't have to worry about multithreading std::cout << "Run()" << std::endl; // Let's connect our stop_cb() signal. This signal tells the client // to exit after 10 iterations uint32_t i = 0; conn = cp.ConnectReadSignal(boost::bind(&stop_cb, &client, i)); // Now, let's run the client. This exits when the client->Stop() function // is called from the callback. client.Run(); // We can also access the client in a multithreaded fashion. std::cout << "StartThread()" << std::endl; // let's first disconnect our previous stop cp.DisconnectReadSignal(conn); // Start the thread, which will handle all message processing. client.StartThread(); // Sleep for 5 seconds. During this time, callbacks should be // fired on every read and output should show up on the display. timespec sleep = {5, 0}; nanosleep(&sleep, NULL); // Instead of sleeping here, we could also be sending commands and reading // directly from the proxy. for (uint32_t j=0; j<10; ++j) { cp.SaveFrame("test"); // all proxies have a iostream operator std::cout << cp << std::endl; } // Now, let's stop the thread. This function only returns after // the thread has been stopped client.StopThread(); std::cout << "finished!" << std::endl; } catch (PlayerCc::PlayerError & e) { // let's output the error std::cerr << e << std::endl; return -1; } return 1; }