Subj : Re: pthreads: cancelling thread blocked on berkeley socket accept() To : comp.programming.threads From : Luke Dalessandro Date : Mon Sep 19 2005 06:36 pm Marcin 'Qrczak' Kowalczyk wrote: > David Hopwood writes: > > >>You should set a shared 'shouldExit' flag and close() the socket >>from the main thread. The listening thread will get an error from >>the accept(), and can then exit when it sees that 'shouldExit' is >>set. > > > I suppose there must be additional memory synchronization because > accept + close don't synchronize memory, right? > Ahh, ok. It's wrapped in C++ so I had the close() call in the Socket object destructor... so to exit I would join/cancel-join all threads, and then "delete" any "newed" sockets. So you're saying that I should move the "close()" call out of the Socket destructor and have an independent "Close()" member on the Socket class? Then add a shouldExit bool wrapped in a mutex inside the Thread class, and then essentially call: Thread* t; Socket* s; t->ShouldExit(true); // locks shouldExit_mutex & sets true s->Close(); // error on Thread t, locks shoudExit and checks t->Join(); delete s; // sockets are always newed in my design delete t; // (if t not statically allocated) Thanks, Luke ------------- Marcin, the abbreviated, not quite ready for prime time, story is basically below. essentially what I have now is (minus all of the checking): note: input directly, not copy, so please mind any obvious typos. class Socket { protected: int _sfd; sockaddr_in _bindData; bool CreateOSSocket(); bool BindOSSocket(int port); int CloseOSSocket(); public: Socket(int port) { if (CreateOSSocket()) BindOSSocket(); } Socket(int sfd, sockaddr_in bindData) : _sfd(sfd), _bindData(bindData) {} virtual ~Socket() { CloseOSSocket(); } bool Listen(); // Caller is responsible for memory, or socket is memory managed // or whatever. Socket* Accept() { sockaddr_in in; int sfd; sfd = accept(_sfd, &in, NULL); return new Socket(sfd, in); } }; class Threadable { public: virtual void operator()() = 0; virtual ~Threadable() {} }; class Thread { protected: thread_t _tid; Threadable* _job; void* Entry(void* pThread) { Thread* tToRun = static_cast(pThread); Threadable* job = tToRun->_job; (*_job)(); return 0; } public: Thread() {} virtual ~Thread() {} void RunJob(Threadable* job) { _job = job; pthread_create(&_tid, NULL, Thread::Entry, this); } void Cancel() { pthread_cancel(_tid); } void Join() { pthread_join(_tid, NULL); } }; class TCPProcess : public Threadable { protected: Socket* _socket; public: TCPProcess(Socket* socket) : _socket(socket) {} virtual ~TCPProcess() { delete _socket; } // Deal with socket (close()), or socket is memory managed... or whatever virtual void operator()() { // Do whatever the process is here } }; class TCPListener : public Threadable { protected: Socket _socket; public: TCPListener(int port) : _socket(port) {} virtual ~TCPListener() {} virtual void operator()() { _socket->Listen(); while (true) { // Singleton call to a thread manager that spawns and memory // manages TCPProcess threads ThreadManager::HandleJob(_socket.Accept()); pthread_testcancel(); // This is what I am worried about } } }; void main(int argc, char * const argv[]) { TCPListener listener(8080); Thread t(); // TCPListener loops on accept() and calls a singleton // ThreadManager to handle connections. ThreadManager not shown. t.RunJob(&listener); string in; while (in != "exit") { cin >> in; } t.Cancel(); t.Join(); ThreadManager::Shutdown(); ThreadManager::Join(); exit(0); } .