.NET BackgroundWorker Multithreading

I have a formless application which acts as a WCF server for several client apps. The concurrency mode of the service is set to single.

The server keeps a collection of transaction objects (w/ fields starttime, endtime, etc..) and the client apps are used to modify and monitor the transactions. e.g. A client can send a "New Transaction" command to add a new transaction to the server, and the changes made would be sent to all connected clients.

Here's what I plan to do:
1. When a client first connects to the server, the server checks the login information of the user and returns the login status (i.e. "successful" or "incorrect password", etc). The server will then create a (deep) copy of the collection and send it to the client asynchronously using background worker.

2. When a client sends a command (e.g. "New Transaction") to the server, the server again validates the command and parameters, then returns a response ("successful"/"invalid"). The transactions that are affected by the command will then be send to all the clients again by making a deep copy and using background worker.

3. I plan to have about 5 backgroundworker objects for maybe 50 or more clients. I will have a "SendList" which stores the data to be send and to which client. The backgroundworker will get the next job from the SendList after it finishes its current job.

Now here are my questions:
1. Aside from locking the transaction collection when creating a deep copy, is there anything else I need to consider for multithreading?
2. Do I need to lock the SendList when adding and retrieving data?

Any other suggestions to implement this are also welcome.

TIA
LVL 22
ThomasianAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
wdosanjosConnect With a Mentor Commented:
We did a PoC for a project that required duplex services.  Everything worked well when both service and client were on the same machine, but as soon as we deployed the service to the server things stopped working.  After a couple days of troubleshooting, we identified that the client's machine firewall was blocking the callbacks from the service.  It's just a matter of opening the port on the client, but that was not an option in our case.

Basically the service does not reuse the connection from the client, so the service creates a new connection to the client on another port.  We tried with NetTcpBinding and WSDualHttpBinding with the same results.

More here. Note the client configuration section on both samples.
http://msdn.microsoft.com/en-us/library/ms752250%28v=VS.90%29.aspx
http://msdn.microsoft.com/en-us/library/ms752216.aspx

Silverlight clients have a PollingDuplexHttpBinding that uses a single communication channel, but unfortunately that's only available in Silverlight.

We may have missed something to make it work, but this summarizes our findings.
0
 
wdosanjosCommented:
1. I you need to check all resources that will be shared among the threads for potential race conditions. Even reads from your transaction collection can fail if other threads are updating the collection.

2. Yes, SendList must be synchronized (locked) for updates and reads.
0
 
ThomasianAuthor Commented:
>>you need to check all resources that will be shared among the threads for potential race conditions.

If I have the WCF's concurrency set to single, does that mean that the only part I need to consider as multithreading is the "DoWork" event of the background worker, is that correct? The events raised by the background would be on the same thread as my main thread right?
0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
wdosanjosCommented:
WCF Single Concurrency only allows one request to be processed at a time, that seems to conflict with your multi-threading requirement.

Regarding the following statement, how does the background worker sends the data back to the client?

The server will then create a (deep) copy of the collection and send it to the client asynchronously using background worker.

BTW, BackgroundWorker is a threading class better suited for the presentation layer (WinForms, WPF).  For server threading, you should consider using the ThreadPool class.

    http://msdn.microsoft.com/en-us/library/system.threading.threadpool.aspx
0
 
ThomasianAuthor Commented:
>>WCF Single Concurrency only allows one request to be processed at a time, that seems to conflict with your multi-threading requirement.
I was thinking of using single concurrency because using multiple concurrency on my case doesn't seem to make any sense. For every client call, I will need to read/write to the collection, so a call from a client can't be processed until a previous call is done. So no multi threading actually occurs even when I set it to multiple concurrency. Or did I misunderstood anything?

>>Regarding the following statement, how does the background worker sends the data back to the client?
By using callbacks.


>>BTW, BackgroundWorker is a threading class better suited for the presentation layer (WinForms, WPF).  For server threading, you should
>>consider using the ThreadPool class.
I need to be able to guarantee the order in which data is received by a client.

e.g. When a client first connects to the server, the "job" of sending the collection is queued on the treadpool. But while sending the data, a new transaction is added. The next "job" is then to send the update to all connected client. Since I'm sending everything asynchronously, I'm afraid that a client might not receive the data in the correct order. i.e. A client receives the update (new transaction) first before receiving the collection.

How do I make this work using ThreadPool?
0
 
wdosanjosCommented:
I'm not sure I'd use single concurrency, but you have a better understanding of the requirements.

Even with BackgroundWorker there is no garantee that threads will execute in a particular order, unless you code for that.  In your case, you need to keep track of each client's state, so that new transactions are not sent to clients unless they have received the collection.

Managing the callbacks can be tricky, because clients can become unreachable for a short time and miss a new transaction callback.  In those cases, you would need to keep track also of what transactions each client have received.  BTW, you might have to open firewall ports on the client for callbacks to work.

An alternative design is for each client to poll the server for new transactions on a regular basis, this could simplify synchronization of new transactions and avoid opening firewall ports.
0
 
ThomasianAuthor Commented:
>>Even with BackgroundWorker there is no garantee that threads will execute in a particular order, ...

I was going to write my own code for this, but I just found out about reliable session which seems to be able to guarantee the order in which data is received.


>>Managing the callbacks can be tricky, because clients can become unreachable for a short time and miss a new transaction callback.

Will I still have this problem when I enabled reliable session?


>>BTW, you might have to open firewall ports on the client for callbacks to work.

I don't understand. Why would firewall be an issue for callbacks? Callbacks won't be opening additional ports, would it?


>>An alternative design is for each client to poll the server for new transactions on a regular basis, ...

If reliable session is able to guarantee that each message is received and in the correct order, is the polling method still recommended?
0
 
wdosanjosCommented:
I don't have experience working with Reliable Session, but from the documentation it seems to address your issue.

Regarding the firewall, callbacks require the server to initiate the connection to the client.  From a client point of view that's inbound traffic coming on a new port.
0
 
ThomasianAuthor Commented:
>>callbacks require the server to initiate the connection to the client.

Wasn't a connection always present when the client first connects to the server? Btw, I forgot to mention that I am using nettcp and pipe binding, not sure if that would make any difference.
0
 
wdosanjosCommented:
I've used nettcp and wshttp bindings with callbacks, and in both cases the server needs to initiate a new connection with the client.  Unfortunately, I never tried with pipe binding.
0
 
ThomasianAuthor Commented:
>>I've used nettcp and wshttp bindings with callbacks, and in both cases the server needs to initiate a new connection with the client.

I'd like to learn more about this. Does the the server use the same port number to connect to the client? Can you tell me how you verified that?
0
 
ThomasianAuthor Commented:
Thanks for all your help.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.