We have a WCF web service operation that is used to generate PDF files. We're using a 3rd party tool to do that (Syncfusion specifically) which we may not be able to replace at the moment.
The problem is that it seems that 3rd party tool has a problem with multi-threading and doesn't work in some cases when there's multiple calls to the web service at the same time.
We can get rid of the problem by using lock
and making sure that only one thread executes the critical section:
Public Class GeneratorController
{
// object we use for lock
private static Object thisLock = new Object();
public void Generate(ref PdfDocument pdfDocument)
{
lock (thisLock)
{
// critical section
}
}
}
My questions is: is that a good idea? Is it going to cause any problems if we have a code like that in a web service?
Note
This is not a question about Syncfusion. This is a question about using lock
in a web service. Do not change tags to syncfusion, please.
The problem I see here is resource starvation.
There is no FIFO rule surrounding locks. So if there's a continuous load, you could get this scenario:
A
claims the lockB
waits for the lockC
waits for the lockA
releases the lock. The lock is arbitrarily given to thread C
D
waits for the lock. Now you have thread B
and D
both waiting.C
releases the lock. Even through thread B
has been waiting the longest, the lock is arbitrarily given to thread D
.And so it continues until the WCF call times out, and you get an impossible-to-reproduce error.
If I had to implement this, I would have a single worker thread dedicated to generating the PDF files. This thread would be launched when the service first starts up, and it waits to pick up a job off a job queue. Each WCF query will place a request on this queue, and there will be some way it can block until it knows the job has been processed.
.NET 4.0 provides the BlockingCollection
class to help with this. (See this question)
This gives you the approach without a complete solution because it isn't a trivial problem. Good luck!
WCF supports synchronized calling of your service objects, depending on your needs, you may want to look into the following two properties:
If you cannot launch multiple instances of 3rd party component, and the component does not allow concurrent acccess (the worst case), then you can specify InstanceContextMode = Single, and ConcurrencyMode = Single; In this case, WCF will only instantiate a single copy of your WCF object (which I assume is a wrapper around 3rd party component), and only one request is processed at a time. The requests will be queued up and processed in a FIFO manner. You don't have to use lock inside your wcf service, since the WCF runtime makes sure you have synchronized access to your wcf objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With