Click to See Complete Forum and Search --> : Can two threads write to a NetworkStream simultaneously?
cjard
November 7th, 2008, 06:04 AM
Just wondering if anyone knows about any syncronization required for NetworkStream. MSDN says that read and write are supported simultaneously, but i'm in a situation where I receive a message over an NS, execute a db query and send a response. If the db is being slow, the client times out. To prevent this, a keep-alive message should be sent at most, every 30 seconds.
I plan to implement a timer and put all current sockets in a dictionary<socket, int>. Every 1000 milliseconds the dictionary value for each socket is incremented, and any that become greater than 25 will have a keep-alive sent and the value will be reset. Send will probably need to be be async..
I'm now asking what happens if my keep-alive thread sends a byte[] at the same time that the db thread sends a byte[]? Anyone know if the buffers intermingle or are they sent in order that they were submitted?
darwen
November 7th, 2008, 06:11 AM
Why not have the keep alive on a separate socket from the data ?
So for every logical connection you'd have 2 sockets : one for keep alives and another for the data.
This would be my preferred approach.
However if you're thread pooling on the server side all the threads may be busy when you receive the keep alive which means this'll time out too.
You could then have 2 thread pools : one for data requests and another for keep alives.
Darwen.
cjard
November 7th, 2008, 07:11 AM
I'm not sure I understand your suggestion. The internationally agreed protocol for this communication states that:
"If the server will take longer than 30 seconds to service the request, it must send a Keep-Alive message to the client"
I have no influence on the client's behaviour, and I cannot make it establish more than one TCP connection to the server. I don't know how this sits with your "two sockets" approach
Further, I cannot at the moment make the entire app asyncronous because I don't know how to run the DB query async.. So the socket handling is async, but the EndXXX naturally has the handling thread created by the system, come into my code and get blocked by the query. Another thread will need to write the Keep-Alive down the TCP channel.
However if you're thread pooling on the server side all the threads may be busy when you receive the keep alive which means this'll time out too
I'm not explicitly pooling, I'm using async networking so the threads are created by the framework or lower subsystem itself. NetworkStream is supposed to be threadsafe w.r.t read/write ops so I presumed there would be at least one thread lying around to service write operations in a reasonably timely fashion..
sotoasty
November 7th, 2008, 07:48 AM
Why not have a "Communication" class and a "Query" class. Have the communtication Class run the DB query on a separate thread, and in the meantime it can send the keep-alive. When the Query class is done, have the communication class get the data from the query class and send the data.
That way you have only one way to send the data/responses.
TheCPUWizard
November 7th, 2008, 08:29 AM
Cjard, I am suprised at you... :(:(
I would have expected you to read the Documentation (http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx):
Read and write operations can be performed simultaneously on an instance of the NetworkStream class without the need for synchronization. As long as there is one unique thread for the write operations and one unique thread for the read operations, there will be no cross-interference between read and write threads and no synchronization is required.
cjard
November 7th, 2008, 08:35 AM
Cjard, I am suprised at you... :(:(
I would have expected you to read the Documentation (http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx):
I read the docs:
MSDN says that read and write are supported simultaneously
I didnt notice the ultimate line, thanks for pointing it out (albeit a little patronisingly).. Now I have to work out how I'm going to have one thread do the writing. It may be easier to just syncronise the access to the NS
cjard
November 7th, 2008, 08:50 AM
Why not have a "Communication" class and a "Query" class. Have the communtication Class run the DB query on a separate thread, and in the meantime it can send the keep-alive. When the Query class is done, have the communication class get the data from the query class and send the data.
That way you have only one way to send the data/responses.
Proposal; I can hopefully split off the DB query to a worker thread and make the main thread Join(25000) it in a limited loop. When the db thread terminates it should have delivered an answer.. If Join returns false then the db worker is still executing so I can send the keepalive and go back to Joining.. Do that up to 10 times, then drop the socket.. I'm marginally concerned that by putting the thread into a loop while it sleeps the time for the Join() ties it up.. though I'm struggling to envisage a way to avoid doing this..
TheCPUWizard
November 7th, 2008, 08:59 AM
...(albeit a little patronisingly)...
It was definately intended more as "Teasing" or "Busting Chops", and definately not Patronizing,so I apologize...
We all iss things at certain times. For me, they fall into two catgories:
1) Incredibly Silly - things a novice would not err on...
2) Incredibly Embarassing - like slamming a multi-ton gun into the deck of a Frigate, or having a speach systhesis system start telling dirty jokes during a presentation to military and congressional leaders. [Yes, both of those are actual events from my past - 1992 and 1987 to be specific....]
cjard
November 17th, 2008, 04:46 AM
I'm back with this one because, though what I implemented worked, I really wanted to use the threadpool rather than making a new thread for each db op
The way it was implemented:
"socket thread" creates a new "worker thread" with a parameterizedthreadstart delegate
The "worker thread" was started, and passed the state object needed to properly query the DB
"socket thread" calls "workerthread".Join(25000) and checks the return value - if it's true, then the query completed and the result is retrieved, if not then a hold message is sent
Moving this into the threadpool is somewhat more of a headscratch for me, because I can't find an easy way to maintain communication with the threadpool thread to know when it has finished. Knowing that Backgroundworker uses the threadpool I could subclass it or use it to do the work, but it then also, via the Completed event manages the invoking necessary to have the creating thread perform the event. This leaves me querying whether the thread will actually be available to run the Completed event; i think not, because it will be in WaitSleepJoin state, in a loop.
I'm thinking that using an AutoResetEvent signaling mechanism might be better; the socket thread can create one, have the threadpool run the query and then wait on on the event, and the threadpool can call set() when it's done. Just niggles me that effectively I feel like i'm creating a backgroundworker because i'll be handling errors, storing them and issuing an event notification to a foreign thread when I'm done.. I'm just not sure how to subclass BGW to reuse its functionality
TheCPUWizard
November 17th, 2008, 06:32 AM
You approach seems to be self defeating...The usual purpose of kicking off a worker thread is so that the starting thread can continue to freely run.
By having a "Join" (or any other "blocking" construct) in your "socket" thread, you are preventing this situation.
IF you can explain, more I can probably give some suggestions.
[Feel free to use PM if there are details not appropriate for the forum...we can always post back the conclusions]
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.