Boost logo

Boost Users :

From: Jason Winnebeck (yg-boost-users_at_[hidden])
Date: 2003-07-22 10:23:03


Peter Dimov wrote:
> Why do you want to test w1 without also doing something with it?
>
> But why do you need to compare weak_ptrs for that?

Perhaps this is a little too direct, but maybe my code can speak for
itself to answer those questions and others from your reply. I
mentioned earlier I was "converting" my network library from straight
pointers to shared_ptr. The code here is from a network pong game
example. The code made sense with pointers, but your comments suggest I
may be misunderstanding the intent of the smart pointers.

Previously I wrote this listener using PongClient* (which is a
ConnectionListener). Now ConnectionListeners are managed by shared_ptr.
  I'm still undecided whether I should try to use shared_ptr for
EVERYTHING in my game (the network code is but the game logic such as
Player is not shared_ptr managed).

The CV (ConditionVariable) has semantics that match pthread_cond with an
associated mutex. The Lock* objects are RAII-style locks, I think they
are most like scoped_lock from boost. The two "on" methods are event
handlers, and getNewConnectionParams is an event called when a new
connection has arrived but has not been negotiated. waitForPlayer is
being called by the "main" thread in the server.

> class OurListener : public ServerConnectionListener {
> public:
> typedef SmartPtr<OurListener> sptr;
> typedef WeakPtr<OurListener> wptr;
>
> protected:
> OurListener(Player* RemotePlayer, Player* LocalPlayer)
> : remotePlayer(RemotePlayer), localPlayer(LocalPlayer), accept(true) {
> }
>
> public:
> /**
> * This listener takes the params it needs to pass them onto the PongClient
> * to set up the game.
> */
> static sptr create( Player* RemotePlayer, Player* LocalPlayer ) {
> sptr ret( new OurListener( RemotePlayer, LocalPlayer ) );
> ret->setThisPointer( ret );
> return ret;
> }
>
> virtual ~OurListener() {}
>
> void onListenFailure(const Error& error, const Address& from, const ConnectionListener::sptr& listener) {
> LockCV lock(sync);
>
> if (listener == connecting.lock()) {
> //Only display an error for our real player. We don't want to see the
> //ConnectionRefused errors.
> LockObject lock( gout );
> gout << "Connection error: " << error << endl;
> gout << " Error received from " << from << endl;
> connecting.reset();
> }
>
> //If waitForPlayer is waiting for the connection, wake it up.
> sync.broadcast();
> }
>
> void onListenSuccess( const ConnectionListener::sptr& listener ) {
> LockCV lock(sync);
>
> player = connecting;
> connecting.reset();
> accept = false;
>
> //If waitForPlayer is waiting for the connection, wake it up.
> sync.broadcast();
> }
>
> void getNewConnectionParams(ConnectionParams& params) {
> LockCV lock(sync);
>
> params.setUnrel(false);
> if (accept && !(connecting.lock()) ) {
> //If no one is connecting and we are accepting connections
> PongClient::sptr temp = PongClient::create( remotePlayer, localPlayer );
> connecting = temp;
> params.setListener( temp );
> } else {
> params.setListener( RefuseClient::create() );
> }
> }
>
> //waitForPlayer returns the connected player, or NULL if the connection
> //process was aborted by the user.
> PongClient::sptr waitForPlayer() {
> LockCV lock(sync);
>
> while (!(player.lock()) && !kbhit()) {
> //We wait for 250ms to recheck kbhit for pressed keys.
> sync.timedWait(250);
> }
> if (!(player.lock())) {
> //We were woken up by a keypress, so refuse any further connections.
> accept = false;
>
> //We don't need to wait around if anyone is in the middle of connecting,
> //because shutting down GNE will close any open connections, and we will
> //be closing down if we aborted this connection.
>
> //Return that no client connected.
> return PongClient::sptr();
> }
>
> return player.lock();
> }
>
> private:
> Player* remotePlayer;
> Player* localPlayer;
>
> //This variable will be non-null when there is a player, so we refuse any
> //other incoming connections. Weak pointer used because we don't want to
> //keep player alive after connect
> PongClient::wptr player;
>
> //player will be stored here while he is connecting, then moved to player
> //when the connection was successful. Weak pointer used because this
> //variable is only temporary and we don't want to keep anything alive.
> PongClient::wptr connecting;
>
> //If this is false, then the user canceled the connection process, we we
> //shouldn't even accept the first player.
> bool accept;
>
> //We use a CV because getNewConnectionParams might be called from
> //different threads, and we want to make sure only one client connects at a
> //time. This protects the state of player.
> //The CV is notified when a new player arrives.
> ConditionVariable sync;
> };

Jason


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net