Jump to content
  • Advertisement
Sign in to follow this  
Telastyn

C++ multi-threading, and derived classes [solved]

This topic is 4748 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am in the process of trying to pick up some multi-threading know-how, and have encountered a problem, that I think I know what it is, but am looking for someone more experienced to confirm. I am using boost::thread on linux... 2.4.27, boost_thread[gcc]1.32, pthreads [unknown version], and gcc version 3.3.5 boost's thread() object takes a functor as its parameter, which is used for the thread starting point. As part of my little test app, I am creating a derived object to a base pointer (the connection *, 2nd line of operator()()):
struct  test_thread_chatter{
        thread_listen_connection        *listener_callback;
        barrier                         *initialization_barrier;
        string                          myname;
        string                          prefix;
        void            operator()(){
                networking              thread_network;
                connection              *tc=thread_network.thread_connect(listener_callback->fetchaddr(), myname, listener_cal
lback);
                string                  s;
                cout << "Thread '"<<myname<<"' started, awaiting input.\n";
                initialization_barrier->wait();
                while(1){
                        thread_network.read();
                        thread_network.send();
                        s=tc->getline();
                        if(s.length()){
                                cout << "Thread '"<<myname<<"':  " << prefix << s <<"\n";
                        }
                        //sleep(5);
                }
        }

        test_thread_chatter(thread_listen_connection    *lcp, barrier *ib, string mn, string pf):listener_callback(lcp), initi
alization_barrier(ib),myname(mn), prefix(pf){}
};





The code when run, spawns the threads nicely, and then segfaults at the tc->getline():
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16386 (LWP 5353)]
0x0804ccb5 in test_thread_chatter::operator() (this=0x80571a0) at syn_test.cc:27
27                              s=tc->getline();
(gdb) display *tc
1: *tc = {_vptr.connection = 0x5, fd = 0, ready = 0, addr = {static npos = 4294967295,
    _M_dataplus = {<std::allocator<char>> = {<No data fields>}, _M_p = 0x0}, static _S_empty_rep_storage = {0, 0, 15, 0}},
  rbuf = {static npos = 4294967295, _M_dataplus = {<std::allocator<char>> = {<No data fields>}, _M_p = 0x40028210 ""},
    static _S_empty_rep_storage = {0, 0, 15, 0}}, sbuf = {static npos = 4294967295,
    _M_dataplus = {<std::allocator<char>> = {<No data fields>}, _M_p = 0x4001f6f0 ""}, static _S_empty_rep_storage = {0, 0,
      15, 0}}}
(gdb) display tc
2: tc = (class connection *) 0xbf7ff88c
(gdb)
Both the pointer of tc, and the _vptr.connection seem wonky here, but I unfortunately only know enough to know they're not right; not enough to know why. I'd guess the derived portion is being sliced, but cannot see where it might occur, the creation is striahgtforward... Similar constructs which don't interact with the threading mechanism tend to have 0x8xxxxxxx for the pointers and _vptr, and seem to work fine. So, is this a by-product of the thread creation? A by-product of boost's thread object? Or just me missing something small? Below is the entirety of the code, sorry about the mess... syn_test.cc
#ifndef _RMSNETWORK_
#define _RMSNETWORK_
#include <iostream>
#include <sstream>
#include <string>
#include <list>

#ifdef _WIN32

#include <winsock.h>
#define socklen_t int

#else

#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>

#endif

#ifndef ENABLE_THREADCONS
	#define ENABLE_THREADCONS	1 
#endif

#define	NETWORK_DEFAULT_PORT	9411

class	networking;
using	namespace	std;

#include <boost/function.hpp>

using	boost::function;

class	connection{
protected:
	int		fd;
	int		ready;
	string		addr;
	string		rbuf;
	string		sbuf;
	virtual int	read(networking&)=0;
	virtual int	send(networking&)=0;
	connection	(int,string&);
	virtual	void	close(){
		#ifndef _WIN32
                        ::close(fd);
                #else
                        closesocket(fd);
                #endif
	}
	virtual ~connection	(){ close(); }
public:
	virtual bool		selectable(){return(0);}
	virtual string		getline();
	virtual void		read(string&);
	virtual void		undoread(string&);
	virtual void		send(string&);
	virtual void		send(char *);
	virtual string		fetchaddr(){return(addr);}
	//friend  ostream&               operator<<(ostream &o, const connection &c);
	friend class	networking;
	virtual int	mtu(){return(1536);}
};

class	tcp_connection:
	public connection{
protected:
	int	read(networking&);
	int	send(networking&);
	tcp_connection(int infd, string& inaddr):connection(infd,inaddr){}
	friend	class 	tcp_listen_connection;
	friend	class	networking;
public:
	bool	selectable(){return(1);}
};

class	tcp_listen_connection:
	public connection{
protected:
	int	read(networking&);
	int	send(networking&){}
	void	accept(networking&);
	tcp_listen_connection(int, string&, string &);
	friend	class networking;
public:
	bool    selectable(){return(1);}
};


class	console_connection:
	public connection{
protected:
	void	ondel(){}
	int	read(networking&);
	int	send(networking &n){ cout << sbuf; sbuf.erase(); }
	console_connection(string c):connection(0,c){}
	friend  class networking;
public:
	#ifndef _WIN32
	bool    selectable(){return(1);}
	#endif
		
};


#if ENABLE_THREADCONS
#include <boost/thread.hpp>
#include <vector>

using   std::vector;
using   namespace       boost;

class   thread_connection:
        public connection{
protected:
        thread_connection       *remote_thread;
        int     read(networking&);
        int     send(networking&);
        thread_connection(string &inaddr, thread_connection *remote=0):connection(0,inaddr){
		if(inaddr.find("->")){
			addr=string("->")+inaddr;
		}
	}

        virtual void    close();


        friend  class   thread_listen_connection;
        friend  class   networking;
        virtual ~thread_connection();
public:
	virtual string          getline();
        virtual void            read(string&);
        virtual void            undoread(string&);
        virtual void            send(string&);
        virtual void            send(char *);
        virtual string          fetchaddr();

        // TODO: mutex protected?
        timed_mutex                     keyhole;
        void                    finish_connection(thread_connection *remote);
};


class   thread_listen_connection:
        public connection{
protected:
        vector<thread_connection *>     oob_cons;
        int     read(networking&);
        int     send(networking&){}
        void    accept(networking&);

        thread_listen_connection(string &inaddr, string &port):connection(0,inaddr){
                addr=string("->") + inaddr;
                if(port.length()){
                        addr=addr + ":" + port;
                }
        }
        virtual void    close(){ready=-1;}
        ~thread_listen_connection();

        friend  class   networking;

public:

	virtual string          getline();
        virtual void            read(string&);
        virtual void            undoread(string&);
        virtual void            send(string&);
        virtual void            send(char *);
        virtual string          fetchaddr();

        timed_mutex                     keyhole;
        void    connect(string inaddr, thread_connection *remote);
};

#endif

	
class	networking{
private:
	// TODO: ban list.
	list<connection *>	connections;
	fd_set			master;
	void			add(connection *);
	void			remove(connection *);
	void			add_fd(connection *);
	struct timeval		*tv;	
	int			maxfd;
	//void			(*on_accept)(tcp_connection *);
	//void			(*on_disconnect)(tcp_connection *);

	function<void(connection *)>	on_accept;
	function<void(connection *)>	on_disconnect;

	friend  void tcp_listen_connection::accept(networking&);
	#if ENABLE_THREADCONS
		friend 	void	thread_listen_connection::accept(networking&);
	#endif
public:

	void		rem_fd(connection *);

	~networking			();
	networking			();
	connection 	*fdtocon	(int);
	connection	*addrtocon	(string);
	int		contofd		(connection *);
	connection	*connect	(string);
	connection	*enable_console	();
	void		disconnect	(connection *);
	void		read();
	void		send();
	int		listen(int,string,string);
	int		listen(int);
	bool		is_banned(string){return(0);}
	struct timeval  timeout();
	void		timeout(struct timeval &);
	//void		set_accept(void (*in)(tcp_connection *)){on_accept=in;}
	//void            set_disconnect(void (*in)(tcp_connection *)){on_disconnect=in;}
	void		set_accept(function<void(connection *)>	in){on_accept=in;}
	void            set_disconnect(function<void(connection *)> in){on_disconnect=in;}



	#if ENABLE_THREADCONS
		// TODO: the connection interface better.
		thread_listen_connection		*thread_listen(string, string="");
		connection				*thread_connect(string, string, thread_listen_connection *);
	#endif	

};


#endif




rmsnetwork.cc
#include "rmsnetwork2.h"
#include <limits>
#include <vector>

using   std::vector;
using	std::string;

/*
ostream&               operator<<(ostream &o, const connection &c){
//
//
//
o << "connection\nfd " << c.fd <<"\naddr "<<c.addr<<"\nend.\n";
return(o);
}
*/

int networking::listen(int queue,string listen_addr,string port)
//
// cut/paste, cut/paste. Listener setup.
//
{

	unsigned long	addr;
        int sockfd;
        int yes=1;
        struct sockaddr_in my_addr;
	tcp_listen_connection	*listener;

        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        my_addr.sin_family = AF_INET;     /* host byte order */
        my_addr.sin_port = htons(atoi(port.c_str())); /* short, network byte order */
        //my_addr.sin_addr.s_addr = INADDR_ANY;
	my_addr.sin_addr.s_addr = inet_addr(listen_addr.c_str());
        bzero(&(my_addr.sin_zero), 8);    /* zero the rest of the struct */

        setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(int)) ;
        /* don't forget your error checking for bind(): */
        if (-1==bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))){
		// TODO: throw an error, or pass to object logger.
		// either way, return.
		return(0);
	}
        if (-1==::listen (sockfd,queue)){
		// TODO: throw and quit.
		return(0);
	}
        // TODO: pass a logger to object
	//printf ("Server started at %s, listening at %i\n",inet_ntoa(my_addr.sin_addr),sockfd);
	// TODO-DONE?: create listen object.
	//  Pass sockfd, addr.
	listener=new tcp_listen_connection(sockfd,port,listen_addr);
	add(listener);
	return(sockfd);
}


int networking::listen(int queue){
//
//
//
string a,b;
stringstream ss;
a="0.0.0.0";
ss << NETWORK_DEFAULT_PORT;
b=ss.str();
return(listen(queue,a,b));
}


connection *networking::connect(string inaddr){
//
// Connect to inaddr.
//


// Assume TCP for now.

// TODO: split this to elsewhere.
string::size_type	x;
string			caddr;
string			cport;

x=inaddr.rfind(":");
if (x!=inaddr.npos && x!=inaddr.length()-1 && x!=inaddr.length()-1 && x!=0){
	cport.assign(inaddr,x+1,inaddr.length());
	caddr.assign(inaddr,0,x);
}else{
	x=inaddr.rfind(" ");
	if (x!=inaddr.npos && x!=inaddr.length()-1 && x!=inaddr.length()-1 && x!=0){
        	cport.assign(inaddr,x+1,inaddr.length());
        	caddr.assign(inaddr,0,x);
	}else{
		caddr=inaddr;
		cport=NETWORK_DEFAULT_PORT;
	}
}

//cout << "debug connect:\nAddr: " << caddr << "\nport: " <<cport <<"\n";


int	sockfd;
int	rtn;
struct sockaddr_in addy;
struct hostent *hostvar;
connection	*c;

sockfd=socket(AF_INET,SOCK_STREAM,0);
// TODO: dns lookups.
addy.sin_family = AF_INET;        /* host byte order */
addy.sin_port = htons(atoi(cport.c_str())); /* short, network byte order */
addy.sin_addr.s_addr = inet_addr(caddr.c_str());
bzero(&(addy.sin_zero), 8);       /* zero the rest of the struct */
rtn=::connect(sockfd, (struct sockaddr *)&addy,sizeof(struct sockaddr));
if (rtn==-1){
	// Error!
	// Throw a connect fail
	return(0);
}
c=new tcp_connection(sockfd,inaddr);
add(c);
return(c);




}



void		networking::disconnect(connection *c){
//
//
//
//close(c->fd);
c->close();
}


connection	*networking::enable_console(){
//
// Add console to connection list if it's not already there.
//
connection			*c;
list<connection *>::iterator	lit;
console_connection		*cc;
string				cname("*console*");

for (lit=connections.begin();lit!=connections.end();++lit){
	c=*lit;
	if (c->fd==0){
		return(c);
	}
}
cc=new console_connection(cname);
add(cc);
return(cc);
}


void    networking_nothing(connection *in){}

	

networking::networking(){
//
// Networking constructor.
//
int	rtn;

// Set tv to defaults.
//  default to non-blocking.
tv=new timeval();
tv->tv_sec=0;
tv->tv_usec=0;

// Set maxfd
maxfd=0;

#ifdef _WIN32
WSADATA wsaData;
rtn=WSAStartup(MAKEWORD(1,1),&wsaData);
if (rtn!=0){
	// Post error!?!
}


#endif

on_accept=networking_nothing;
on_disconnect=networking_nothing;


}


networking::~networking(){
//
//
//
list<connection *>::iterator	cit;

for (cit=connections.begin();cit!=connections.end();++cit){
	delete *cit;
}
}

void	networking::add(connection *c){
//
// Add connection to list.
//
// TODO: retrieve dupes, and remove old?

connections.push_back(c);
if(c->selectable()){
	add_fd(c);
}
}

void	networking::add_fd(connection *c){
//
// Add fd to set.
//
FD_SET(c->fd,&master);
if (c->fd>maxfd){maxfd=c->fd;}
}

void	networking::rem_fd(connection *c){
//
// rem fd from set.
//
FD_CLR(c->fd,&master);
}

void	networking::read(){
//
// Run select, set ready, call reads.
//
fd_set		tmp;
int		rtn;
connection	*c;
list<connection *>::iterator	cit;
list<connection *>::iterator	e=connections.end();

if (connections.empty()){return;}
tmp=master;
select(maxfd+1,&tmp,0,0,tv);
for (cit=connections.begin();cit!=e;++cit){
	c=*cit;
	if (c->ready!=-1){
		if(c->selectable()){
			if (FD_ISSET(c->fd,&tmp)){
				c->ready=1;
			}else{
				c->ready=0;
			}
		}else{
			c->ready=1;
		}
	c->read(*this);
	}
}
}


void	networking::send(){
//
// Eerily similar to read...
//
fd_set          tmp;
int             rtn;
connection      *c;
list<connection *>::iterator    cit;
list<connection *>::iterator    e=connections.end();

if (connections.empty()){return;}
tmp=master;
select(maxfd+1,0,&tmp,0,tv);
for (cit=connections.begin();cit!=e;++cit){
        c=*cit;
        // TODO: change this if c is a windows stdin.
        if (c->ready!=-1){
                if (FD_ISSET(c->fd,&tmp)){
                        c->ready=1;
                }else{
                        c->ready=0;
                }
        c->send(*this);
        }
}
}



int	networking::contofd(connection *c){
//
// Return copy of fd from connection.
//
return(c->fd);
}
	

connection	*networking::addrtocon(string inaddr){
//
//
//
list<connection *>::iterator		it;

for(it=connections.begin(); it!=connections.end(); ++it){
	if((*it)->addr==inaddr){
		return(*it);
	}
}
return(0);
}

connection::connection(int sock,string &inaddr){
//
//
//
ready=0;
fd=sock;
addr=inaddr;
//sbuf="moo";
}


string	connection::getline(){
//
//
//
string::size_type       x;
string	rtn;

// TODO: why isn't getline being used here?
if (rbuf.empty()){return(rtn);}
x=rbuf.find_first_of("\r\n");
rtn=rbuf.substr(0,x);
if (x!=rbuf.length()){
	x=rbuf.find_first_not_of("\r\n",x);
	if (x!=rbuf.npos){
		rbuf=rbuf.substr(x,rbuf.length());
	}else{
		rbuf.clear();
	}
}else{
	rbuf.clear();
}
return(rtn);
}


void	connection::send(string &in){
//
//
//
sbuf=sbuf+in;
}


void	connection::send(char *in){
//
//
//
string tmp=in;
send(tmp);
}


void	connection::read(string &out){
//
// Read 1 line into string
//
out=connection::getline();
}

void	connection::undoread(string &in){
//
// Undo a read();
//
if (in[in.length()]!='\n'){
	in=in+"\n";
}
rbuf=in+rbuf;
}



int     tcp_connection::read(networking &n){
//
// Read data from socket if ready
//
string  s;
char    *buf;
int     len=mtu();
int     rtn;
if (ready!=1){
        return(0);
}
buf=(char *)malloc(len);
bzero(buf,len);
rtn=recv(fd,buf,len,0);
if (rtn<1){
        // disconnection!
        //  TODO: toss some sort of on-d/c
        //   but for now, just unready.
	n.on_disconnect(this);
        ready=-1;
	n.rem_fd(this);
        free(buf);
        return(rtn);
}
// TODO: see if string has a pre-pend
rbuf.append(buf);
//cout << "in tcp::read(): " << fd << ":" << addr << ":" << rtn << ": " << buf << " -> " << rbuf << "\n";
free(buf);
return(rtn);
}


int	tcp_connection::send(networking &n){
//
// Send data from socket if ready
//
int	rtn;
int	len=mtu();
int	reallen;

if (ready!=1){
	return(0);
}
reallen=sbuf.length();
if (reallen>len){
	reallen=len;
}
rtn=::send(fd,sbuf.c_str(),reallen,0);
if (rtn<0){
	// disconnection!
	// TODO: toss a d/c.
	n.on_disconnect(this);
	ready=-1;
	n.rem_fd(this);
	return(rtn);
}
if (rtn){
	sbuf.erase(0,rtn);
}
return(rtn);

}


tcp_listen_connection::tcp_listen_connection(int sock,string &port, string &inaddr):connection(sock,inaddr){
//
// Create listening socket connection object.
//
addr=inaddr +":"+port;
}


int	tcp_listen_connection::read(networking &n){
//
// Check if ready. If so, send to accept!
//
if (ready==1){
	accept(n);
	ready=0;
}
}



void	tcp_listen_connection::accept(networking &n){
//
// Yay, new connection. Accept it, and add to networking.
//
tcp_connection		*tcpc;
int			newfd;
int			sinsize;
struct sockaddr_in	insock;
string			tmpaddr;

newfd=::accept(fd,(struct sockaddr *)&insock,(socklen_t *)&sinsize);
if (!newfd){
	// Error.
	// Report it.
	return;
}
tmpaddr=inet_ntoa(insock.sin_addr);
if (n.is_banned(tmpaddr)){
	// IP banned.
	// TODO: post message to client?
	close();
	n.rem_fd(this);
	return;
}
// New connection.
//  TODO: make a mechanism to post "new player" somewhere.
tcpc=new tcp_connection(newfd,tmpaddr);
n.add(tcpc);
n.on_accept(tcpc);
}





int	console_connection::read(networking &n){
//
// Read from kb.
//
char     	*buf;
int             len=mtu();
unsigned long	rtn;

if (ready!=1){
	return(0);
}
buf=(char *)malloc(len);
bzero(buf,len);

#ifdef	_WIN32	
	ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE),buf,rtn-2,&bread,0);
#else
	rtn=::read(fd,buf,len-2);
#endif

rbuf=rbuf+buf;
free(buf);
#ifdef _WIN32
if (rtn>numeric_limits<int>::max()){
	return(numeric_limits<int>::max());
}else{
#endif
	return(rtn);
#ifdef _WIN32
}
#endif
}	


#if	ENABLE_THREADCONS


int     thread_listen_connection::read(networking &n){
//
// Called by networking when it's going to accept queued connections.
//
try{
        timed_mutex::scoped_try_lock    tl(keyhole);
}catch (boost::lock_error le){
        return(0);
        //
        // eh, try again later.
        //
}
//
// Locked to prevent new connections from interfering.
//
// Push stored connections into networking.
//
accept(n);
}


void    thread_listen_connection::accept(networking &n){
//
// Should only ever be called by tlc::read().
//
// TODO: force that programatically.
//

// THREADING-NOTE: read (above) holds the lock here.

vector<thread_connection *>::iterator   it;

for (it=oob_cons.begin(); it!=oob_cons.end(); ++it){
        n.add(*it);
        n.on_accept(*it);
}
oob_cons.clear();
}



void    thread_listen_connection::connect(string inaddr, thread_connection *remote){
//
// Called by a remote thread in order to establish a connection.
//
// BLOCKING.
//
// inaddr is the remote thread addr.
// remote is a pointer to the remote thread's pre-made connection,
//

timed_mutex::scoped_lock sl(keyhole);

thread_connection       *tc=new thread_connection(inaddr,remote);
oob_cons.push_back(tc);
remote->finish_connection(tc);
}


thread_listen_connection::~thread_listen_connection(){
//
// Closing app?
//
timed_mutex::scoped_lock sl(keyhole);

vector<thread_connection *>::iterator   it;

for (it=oob_cons.begin(); it!=oob_cons.end(); ++it){
        delete *it;
}
oob_cons.clear();
}


string	thread_listen_connection::getline(){}
void	thread_listen_connection::read(string &s){}
void	thread_listen_connection::undoread(string &s){}
void	thread_listen_connection::send(string &s){}
void	thread_listen_connection::send(char *s){}
string	thread_listen_connection::fetchaddr(){ timed_mutex::scoped_lock sl(keyhole); return(addr);}

string	thread_connection::getline(){
//
//
//
try{
	timed_mutex::scoped_try_lock tl(keyhole);
}catch (lock_error le){
	return("");
}

return(connection::getline());

}


void	thread_connection::read(string &s){
//
//
//
try{
        timed_mutex::scoped_try_lock tl(keyhole);
}catch (lock_error le){
	// TODO: can I even set s here?
        return;
}

s=rbuf;
rbuf.clear();
}


void	thread_connection::undoread(string &s){ /* TBD */ }
void	thread_connection::send(string &s){
//
//
//
timed_mutex::scoped_lock sl(keyhole);

sbuf.append(s);
}

void	thread_connection::send(char *s){
//
//
//
timed_mutex::scoped_lock sl(keyhole);

sbuf.append(s);
}


string	thread_connection::fetchaddr(){ timed_mutex::scoped_lock sl(keyhole); return(addr);}


void            thread_connection::finish_connection(thread_connection  *remote){
//
// finish the thread connection by setting the remote pointer.
//
//
// Note: should probably check for the 'good' null pointer, but even if the programmer was malicious enough
//        to try and finish a connection to a connection that didn't start it, what could we do?
//
//
// BLOCKING
//

timed_mutex::scoped_lock sl(keyhole);

remote_thread=remote;
}

/*
void            thread_connection::close(){
//
//
//

timed_mutex::scoped_lock sl(keyhole);
ready=-1;
timed_mutex::scoped_lock sl2(remote->keyhole);
remote->ready=-1;
}
*/

void            thread_connection::close(){
//
// TODO: determine disconnect strategy.
//
}


thread_connection::~thread_connection(){
//
// TODO:...
//
}


int             thread_connection::send(networking &n){
//
//
//
try{
        timed_mutex::scoped_try_lock tl(keyhole);
}catch(lock_error le){
        return(0);
}

// TODO: test disconnection...
int     rtnlen=sbuf.length();

if (!rtnlen){
        return(0);
}

//
// Yay, something to send.
//
// Try to lock partner's buffer and append.
//

try{
        timed_mutex::scoped_try_lock    tl(remote_thread->keyhole);
}catch (lock_error les){
        //
        // eh, busy. try again later.
        //
        return(0);
}

remote_thread->rbuf.append(sbuf);
sbuf="";
return(rtnlen);
}



int             thread_connection::read(networking &n){
//
// Nothing really. The rbuf will be filled by partner's sends.
//
try{
	timed_mutex::scoped_try_lock	tl(keyhole);
}catch	(lock_error le){
	return(0);
}
return(rbuf.length());
}


thread_listen_connection	*networking::thread_listen(string inaddr, string inport){
//
//
//
thread_listen_connection        *tlc=new thread_listen_connection(inaddr,inport);
add(tlc);
return(tlc);
}


connection      *networking::thread_connect(string inaddr, string thisthread, thread_listen_connection *remote){
//
// BLOCKING.
//
// If remote->addr==inaddr, create thread_connection, add and return.
//
timed_mutex::scoped_lock        sl(remote->keyhole);

if(remote->addr!=inaddr){
        //
        // Bogus address?
        //
        // TODO: use this?
        //
        return(0);
}
string          tt=thisthread;
if (thisthread.find("->")){
        string  tt=string("->")+thisthread;
}
thread_connection       *tc=new thread_connection(inaddr);
// unlock so the finishing connection can go.
sl.unlock();
remote->connect(thisthread,tc);
add(tc);
}
#endif





compiled as: g++ -pthread -lboost_thread -g2 -o syn_test syn_test.cc rmsnetwork2.cc [Edited by - Telastyn on September 25, 2005 12:29:47 AM]

Share this post


Link to post
Share on other sites
Advertisement
My guess is that thread_connect is not working properly. Is it returning 0?
Is it giving up the lock too early?
I doubt this is your problem, but writes to cout should be syncronized, otherwise you can have funky output if two threads try to dump at the same time.

Share this post


Link to post
Share on other sites
Sigh, never mind. It didn't return null, it returned garbage because I didn't specify a return. And I know the output will be out of order or otherwise unreliable. I thought gcc prodduced warnings for no return... alas.

It dies elsewhere now, but that is something I can deal with.
Thank you for your post.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!