threads and signals question
Hi all, I guess my question is not specific to Boost.Thread, but to threading in general (I'm new at it)... still hope you can help me out, either directly or by redirecting me to the right place (links are very much appreciated) I'm starting a multi-threaded program using Boost.Thread library: it is a "server", in which a thread loops around a "select" to accept new connections and see when a socket has data to be read, in which case puts the fds in queue from which other threads are taking them out to read the data. The problem I have, is that when a "ReceiverThread" finishes reading the data from the socket, it puts the fd back in the "all connections list", but by this time the other ("main")thread already copied the fds from the list and got into the next "select" loop, which means the socket from which the "receiver" just finished reading, will not be "selected" (monitored) untill the next select loop, which will not be untill a) a new connection comes or b)one of the other connected sockets gets some data that takes makes the main thread return from select. reading the select man, I thought I could just use a signal to force select to return when the "receiver" has put the fd back in the "all connection list": the threads are now executing something like: main_thread { *put all fds from "all sockets" list into a fdset *make a select on the fdset (block till something interesting happens) *take the fds with data out of "all sockets" and put them into "sockets with data" *loop } receiver{ *get a fd from "sockets with data" (if nothing there blocks till the main_thread sends us a fd through the queue) *read from fd *put fd back into "all sockets" (problem: main_thread may be (is!) already into the select) *raise(SIGUSR1) (to force select to return and enter the loop again, but this time with our fd) } the signal handler for SIGUSR1 does nothing, it just serves to force select to return, but the code is not really working as I expected, and I realized that the problem is that each thread has its own pid, so it seems raise is actually sending a signal to the wrong thread.... as I said, I am new to mulithreading, but I thought all threads run in a process, which means, they all have the same pid. ->if I first find out the "pid" of the main_thread and change raise(SIGUSR1) to kill(pid,SIGUSR1) it works ok. so my question: why does each thread have a own pid?? how can then I send signals from one thread to another?? I discovered there is a "pthread_kill" function to send signals to specific threads, the problem is I only have boost::thread objects, no pthread_t structures. or am I talking nonsense and shouldnt be using signals with Boost.Thread? if so, how do I solve the select problem?? thanx! luis
On Wednesday 28 August 2002 10:39 pm, lparrab wrote:
or am I talking nonsense and shouldnt be using signals with Boost.Thread? if so, how do I solve the select problem??
IMHO I wouldn't use select. Each time a new connections is initiated, you can simply start a new thread to receive data from that socket. I don't know what performance impact this would have, but the code will certainly be simpler and easier to maintain. Just my 2 pence. Tom Howard
IMHO I wouldn't use select. Each time a new connections is initiated, you can simply start a new thread to receive data from that socket. I don't know what performance impact this would have, but the code will certainly be simpler and easier to maintain.
as I said, I'm new to threads.. and I know they are much more "leightweighted" than a normal process, but imagine a server, like an application server, which can have *a lot* of clients connected at the same time, but in which the clients are not really all requesting thigs all the time, they are "just connected" I think having a thread waiting on each open connection is not the right approach here, so I thought of going a kind of "production line" approach in which a few threads (5-10) are reading the data from a bunch of open connections (50-100), the only thing they do is read the data, parse it and form a "Request" which they put in a queue for further processing and then go on to service the other connections. Then another group of threads is taking this requests and doing something, and putting Response objects in yet another queue, which another group of threads "Sender" is taking and sending thorugh the socket. I think you get the idea: a frew threads just doing one thing and then passing the processing to another gorup of threads. I know having a thread dedicated to each connection would be much easier, but since this project is mostly for fun (and to learn!) I'd like to take a "better" approach (note that I am not saying the approach I just described is the best one, but right now it sounds more efficient and scalable to me than the one-trhead-per-connection approach) regards, luis.l
Hi, On Thursday 29 August 2002 4:37 pm, Luis De la Parra wrote:
I know having a thread dedicated to each connection would be much easier, but since this project is mostly for fun (and to learn!) I'd like to take a "better" approach (note that I am not saying the approach I just described is the best one, but right now it sounds more efficient and scalable to me than the one-trhead-per-connection approach)
The approach may or may no be better depending on the point of view. A few time now I've read that the best time to optimise is later and what you may find you are doing is optimising to early and be doing so making the design overly complex, but I might be guiding you in the wrong direction so let's pursue the current design. Currently you are doing the select in one thread and passing the file descriptors of to another thread for the reading. There are only a couple of ways to put the fd back into the set of fd's being selected on and they all require a new call to select. You've covered two of these yourself, which is to wait for select to return (which could lead to huge delays waiting for activity on another fd) and to force select to return by using a signal. The only otherway is to specify a timeout on the select, but given the three choices I would go for the signal approach. The other option that you may have is to recv in the same thread as the select, it then passes the received data to another thread or threads for processing and goes back to the select. I suspect that most your receives will be serialised anyway as they will in most cased be coming from the same network interface, but I really don't know enough about the low levels of networking and how it's handled by the OS. Given the C APIs I'm fine, but below that is guess work. Anyway if the receives are going to be serialised by the OS of the interface itself, then you may as well do the recv's in the same thread as the select and that way you no longer have to worry about signalling to interrupt the selects. Apart from that I can't think of any nice solutions apart from the one you have already suggested. Cheers, Tom
Luis, IMO, if you have to go through weird hoops or gyrations to make threads work for an application, then one of twop things is wrong. Either the task just isn't conducive to threads, or the approach being taken is wrong, and you need to step back and take a broader look at what you are trying to do. In your situation, you would typically have the main thread with a socket listening on a "well known" port for new connections. It would then create a new socket, bind the new socket to that connection, then spawn a new thread to handle just that socket. There really isn't much overhead to a thread, you can have lots of them. The beauty of this is that the main thread doesn't care about the sockets it has spawned off. If the socket connection dies, the thread just terminates. Since the main socket is only listening for connection requests, it doesn't need to manage the other sockets, let the individual threads do that.
Hi all,
I guess my question is not specific to Boost.Thread, but to threading in general (I'm new at it)... still hope you can help me out, either directly or by redirecting me to the right place (links are very much appreciated)
I'm starting a multi-threaded program using Boost.Thread library: it is a "server", in which a thread loops around a "select" to accept new connections and see when a socket has data to be read, in which case puts the fds in queue from which other threads are taking them out to read the data. The problem I have, is that when a "ReceiverThread" finishes reading the data from the socket, it puts the fd back in the "all connections list", but by this time the other ("main")thread already copied the fds from the list and got into the next "select" loop, which means the socket from which the "receiver" just finished reading, will not be "selected" (monitored) untill the next select loop, which will not be untill a) a new connection comes or b)one of the other connected sockets gets some data that takes makes the main thread return from select.
Russ Poffenberger Engineering Specialist NPTest, Inc. rpoffenberger@nptest.com
On Thursday 29 August 2002 3:13 pm, Russ Poffenberger wrote:
In your situation, you would typically have the main thread with a socket listening on a "well known" port for new connections. It would then create a new socket, bind the new socket to that connection, then spawn a new thread to handle just that socket. There really isn't much overhead to a thread, you can have lots of them. The beauty of this is that the main thread doesn't care about the sockets it has spawned off. If the socket connection dies, the thread just terminates. Since the main socket is only listening for connection requests, it doesn't need to manage the other sockets, let the individual threads do that.
This is an awful design for any server that handles lots of connections, there's way too much thread contention to be efficient. - Dale.
participants (5)
-
Dale Peakall
-
lparrab
-
Luis De la Parra
-
Russ Poffenberger
-
Tom Howard