views:

223

answers:

7

Hi. I have a TCP Server application that serves each client in a new thread using POSIX Threads and C++.

The server calls "listen" on its socket and when a client connects, it makes a new object of class Client. The new object runs in its own thread and processes the client's requests.

When a client disconnects, i want some way to tell my main() thread that this thread is done, and main() can delete this object and log something like "Client disconnected".

My question is, how do i tell to the main thread, that a thread is done ?

+2  A: 

The most straightforward way that I can see, is to join the threads. See here. The idea is that on a join call, a command thread will then wait until worker threads exit, and then resume.

Alternatively, you could roll something up with some shared variables and mutexes.

Rob Lachlan
+1  A: 

You could use a queue of "thread objects to be deleted", protect access to the queue with a mutex, and then signal a pthread condition variable to indicate that something was available on the queue.

But do you really want to do that? A better model is for each thread to just clean up after itself, and not worry about synchronizing with the main thread in the first place.

David Gelhar
OK. I think the idea with selfcleaning threads is good. But is it OK to call the destructor right from the object itself ?
milleroff
Yes, you can call "delete this" from the object itself, provided you follow some rules. For example, the object must not be allocated on the stack, and the main thread is not allowed to refer to the object once it creates the processing thread (because the thread may terminate at any time). See http://stackoverflow.com/questions/447379/what-is-the-use-of-delete-this
David Gelhar
+2  A: 

pthreads return 0 if everything went okay or they return errno if something didn't work.

int ret, joined;
ret = pthread_create(&thread, NULL, connect, (void*) args);
joined = pthread_join(&thread, NULL);

If joined is zero, the thread is done. Clean up that thread's object.

David Titarenco
No, that's not right. "pthread_create" returns 0 to mean that the thread has been created successfully, it doesn't mean that it's done (or even, in fact, that it has had a chance to run at all).
David Gelhar
My mistake, meant to write pthread_join, don't know what I was thinking
David Titarenco
That's wrong, really. if ret is zero, it means the thread was created successfully and nothing more.
Hasturkun
Yep, Hasturkun, fixed
David Titarenco
This *blocks* the calling thread, waiting for the new one to finish. If the listener thread does this, it's stuck and can't serve any more requests. The listener should only do this after it knows the client thread is finished. But that just brings us back to the original question: How do you know when the client thread is finished?
Rob Kennedy
+2  A: 

If the child thread is really exiting when it is done (rather than waiting for more work), the parent thread can call pthread_join on it which will block until the child thread exits.

Obviously, if the parent thread is doing other things, it can't constantly be blocking on pthread_join, so you need a way to send a message to the main thread to tell it to call pthread_join. There are a number of IPC mechanisms that you could use for this, but in your particular case (a TCP server), I suspect the main thread is probably a select loop, right? If that's the case, I would recommend using pipe to create a logical pipe, and have the read descriptor for the pipe be one of the descriptors that the main thread selects from.

When a child thread is done, it would then write some sort of message to the pipe saying "I'm Done!" and then the server would know to call pthread_join on that thread and then do whatever else it needs to do when a connection finishes.

Note that you don't have to call pthread_join on a finished child thread, unless you need its return value. However, it is generally a good idea to do so if the child thread has any access to shared resources, since when pthread_join returns without error, it assures you that the child thread is really gone and not in some intermediate state between having sent the "I'm Done!" message and actually having exited.

Tyler McHenry
@Tyler, I believe you leak resources if you don't either join or detach the thread.
Michael Aaron Safyan
@Michael You're correct. If you're not going to call join, you should detach.
Tyler McHenry
A: 

Calling pthread_join will block execution of the main thread. Given the description of the problem I don't think it will provide the desired solution.

My preferred solution, in most cases, would be to have the thread perform its own cleanup. If that isn't possible you'll either have to use some kind of polling scheme with shared variables (just remember to make them thread safe, hint:volatile), or perhaps some sort of OS dependant callback mechanism. Remember, you want to be blocked on the call to listen, so really consider having the thread clean itself up.

torak
Declaring shared variables as "volatile" does not automatically make them thread safe. There are many discussions on the Net and SO that explain why that is the case. Rely on the appropriate synchronization mechanism (mutex, etc) or atomic operation to be sure.
Void
A: 

While it is possible to implement IPC mechanisms to notify a main thread when other threads are about to terminate, if you want to do something when a thread terminates you should try to let the terminating thread do it itself.

You might look into using pthread_cleanup_push() to establish a routine to be called when the thread is cancelled or exits. Another option might be to use pthread_key_create() to create a thread-specific data key and associated destructor function.

If you don't want to call pthread_join() from the main thread due to blocking, you should detach the client threads by either setting it as option when creating the thread or calling pthread_detach().

jschmier
A: 

As others have mentioned, it's easy to handle termination of a given thread with pthread_join. But a weak spot of pthreads is funneling information from several sources into a synchronous stream. (Alternately, you could say its strong spot is performance.)

By far the easiest solution for you would be to handle cleanup in the worker thread. Log the disconnection (add a mutex to the log), delete resources as appropriate, and exit the worker thread without signaling the parent.

Adding mutexes to allow manipulation of shared resources is a tough problem, so be flexible and creative. Always err on caution when synchronizing, and profile before optimizing.

Potatoswatter