Single "lock" or separate reader/writer locks for IO operations? - c#

I have a few threads writing and reading different files.
Is it ok to use a single lock {} (the same variable for all protected regions) for all disk operations? So I don't have two threads simultaneously reading and writing to disk to about seeks?
I also heard that I could also use on thread for reads and another for writes, is this always true? why?

If each thread reads or writes to a different file, I don't see why you need concurrency.
Usually, there are multiple threads accessing the same file (resource) for reading and writing.
In that scenario, when a thread is writing to the file, all the other threads have to wait.
This is a classic concurrency problem called "Readers-Writers".
You can find more information here:
http://en.wikipedia.org/wiki/Readers-writers_problem

If you are not accessing code of other thread from any thread then one object for synchronization would be enough but it would increase the thread queue waiting for resource. One sync object for each resource or group of resource would be better option

Your requirement seems somewhat confusing and morphs. One comment says 'the threads are writing to the same file' and another 'all write to the same collection of files simultaneously'.
There are some choices:
1) Lock up the reads and writes with one lock. this is the simplest method but has the highest probability of contention between the calling threads because the lock is held for the duration of a disk operation.
2) Lock up the reads and writes with one reader/writer lock per file - this is better than (1) in that contentin on different files does not happen. There could still be contention between reads/writes to the same file.
2) Queueing off the reads/writes to one writer thread. This tends to exercise the disk more because it has to swap around between files as it dequeues and executes write requests, but minimizes write contention in the calling threads - they only have to lock a queue for the time taken to push a pointer on. Reading becomes a slow operation because the calling threads would have to wait on a synchro object until their read request is completed. Low contention on writes but high latency on all reads.
3) Like (2), but using a thread per file. This can get expensive memory-wise for several files and only really helps over (2) if the output files are spread over several physical disks. Like (2), low contention and slow reads.
4) Queueing off the writes as threadpool tasks. I'm not sure how to do this exactly - the file context would have to be passed as a parameter and access to it would probably need locking up - this may not work effectively. Like (2), low contention and slow reads.
5) Redesign your app to avoid this requirement entirely?

Using only one lock could slow your application. If a thread is writing a file for a long time, maybe other threads should be allowed to read some other files.
Could you be more precise on how which threads access which files?

Related

Writing files efficiently — Collect or write immediately

Is there a performance difference for file I/O between the following two approaches?
Use a queue that is filled by producers and start a task writing to disk after all data has arrived
Have a task writing to disk in parallel to producers
The data is written to different files and multiple directories.
A separate task for the I/O and Parallel.ForEach would be used in both cases.
I would assume that the second version would perform better, theoretically the producers and the I/O are really concurrent. Since I/O causes interrupts to the calling process I was wondering if there would be a down-side. This might cause overhead that outweighs the benefits of parallelism.
Are there situations were I should favor the first solution over the second?
I would assume that the second version would perform better
If the multiple directories are still on the same physical drive you will likely get worse performance with the 2nd option.
There are some edge cases where writing in parallel (and limiting yourself to only 2 or 3 threads) can be faster. For example writing 1000's of 1kb files would perform better in a slightly parallel fasion due to the overhead costs of creating a file outweighing the IO costs of writing to the file. But if you where writing 1000's of 1mb files then having a single thread doing the writing would likely be faster.
A easy way to implement this is use TPL Dataflow, you can have a highly parallel TransformBlock but then have that connected to a 1 or 2 threaded ActionBlock which performs the writes. You then limit the input buffer of the ActionBlock when you set up the link and the TransformBlock will block producers if the pipeline is full without taking up a lot of memory.
I'm not sure of what you mean by your second task. I think you're talking about using a concurrent queue of some kind, and a consumer thread that services it. The producers write to that queue. The consumer thread waits for information to be added to the queue, and writes that information to disk. That way, the consumer can be writing to disk while producers are processing and adding things to the queue. There's no need to wait for all information to arrive.
I've had a lot of success using BlockingCollection for things like this.
If that's what you're talking about, then it should perform much better than your first option because, as you say, the disk I/O thread and the producer threads are executing concurrently.

C# processing received socket data via threads

I have a problem with scalability and processing and I want to get the opinion of the stack overflow community.
I basically have XML data coming down a socket and I want to process that data. For each XML line sent processing can include writing to a text file, opening a socket to another server and using various database queries; all of which take time.
At the minute my solution involves the following threads:
Thread 1
Accepts incoming sockets and thus generates child threads that handle each socket (there will only be a couple of incoming sockets from clients). When an XML line comes through (ReadLine() method on StreamReader) I basically put this line into a Queue, which is accessible via a static method on a class. This static method contains locking logic to ensure that the program is threadsafe (I could use Concurrent Queue for this of course instead of manual locking).
Threads 2-5
Constantly take XML lines from the queue and processes them one at a time (database queries, file writes etc).
This method seems to be working but I was curious if there is a better way of doing things because this seems very crude. If I take the processing that threads 2-5 do into thread 1 this results in extremely slow performance, which I expected, so I created my worker threads (2-5).
I appreciate I could replace threads 2-5 with a thread pool but the thread pool would still be reading from the same Queue of XML lines so I wandered if there is a more efficient way of processing these events instead of using the Queue?
A queue1 is the right approach. But I would certainly move from manual thread control to the thread pool (and thus I don't need to do thread management) and let it manage the number of threads.2
But in the end there is only so much processing a single computer (however expensive) can do. At some point one of memory size, CPU-memory bandwidth, storage IO, network IO, … is going to be saturated. At that point using an external queuing system (MSMQ, WebSphere*MQ, Rabbit-MQ, …) with each task being a separate message allows many workers on many computers to process the data ("competing consumers" pattern).
1 I would move immediately to ConcurrentQueue: getting locking right is hard, the more you don't need to do it yourself the better.
2 At some point you might find you need more control than the thread pool providers, that is the time to switch to a custom thread pool. But prototype and test: it is quite possible your implementation will actually be worse: see paragraph 2.

Read/Write locking confusion

I'm not entirely sure how best accomplish this multi-threading scenario so any input would be appreciated.
I have one block, that reads data, that several threads can access at once. I have another block that writes data, only one thread can write at any time. Also it can't start writing as long as any thread is reading the data. Is ReaderWriterLockSlim the way to go here, will it wait for the read threads to exit before blocking the thread for writing?
Yes, ReaderWriterLockSlim is perfect for frequent reader/infrequent writer scenarios.
The behaviour is as you guessed - single writer only, writers block until all readers are done, readers cannot access while writer is in process.
Be careful that the time you hold the lock (whether for read or write) is long enough to prevent any concurrent access, and no longer.
Yes, it sounds like ReaderWriterLockSlim is what you want.
A write lock will not be acquired as long as read locks are in place. I suggest you read the documentation for a complete description of the behavior (locking queues, etc):
http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

ReaderWriterLock vs lock{}

Please explain what are the main differences and when should I use what.
The focus on web multi-threaded applications.
lock allows only one thread to execute the code at the same time. ReaderWriterLock may allow multiple threads to read at the same time or have exclusive access for writing, so it might be more efficient. If you are using .NET 3.5 ReaderWriterLockSlim is even faster. So if your shared resource is being read more often than being written, use ReaderWriterLockSlim. A good example for using it is a file that you read very often (on each request) and you update the contents of the file rarely. So when you read from the file you enter a read lock so that many requests can open it for reading and when you decide to write you enter a write lock. Using a lock on the file will basically mean that you can serve one request at a time.
Consider using ReaderWriterLock if you have lots of threads that only need to read the data and these threads are getting blocked waiting for the lock and and you don’t often need to change the data.
However ReaderWriterLock may block a thread that is waiting to write for a long time.
Therefore only use ReaderWriterLock after you have confirmed you get high contention for the lock in “real life” and you have confirmed you can’t redesign your locking design to reduce how long the lock is held for.
Also consider if you can't rather store the shared data in a database and let it take care of all the locking, as this is a lot less likely to give you a hard time tracking down bugs, iff a database is fast enough for your application.
In some cases you may also be able to use the Aps.net cache to handle shared data, and just remove the item from the cache when the data changes. The next read can put a fresh copy in the cache.
Remember
"The best kind of locking is the
locking you don't need (i.e. don't
share data between threads)."
Monitor and the underlying "syncblock" that can be associated with any reference object—the underlying mechanism under C#'s lock—support exclusive execution. Only one thread can ever have the lock. This is simple and efficient.
ReaderWriterLock (or, in V3.5, the better ReaderWriterLockSlim) provide a more complex model. Avoid unless you know it will be more efficient (i.e. have performance measurements to support yourself).
The best kind of locking is the locking you don't need (i.e. don't share data between threads).
ReaderWriterLock allows you to have multiple threads hold the ReadLock at the same time... so that your shared data can be consumed by many threads at once. As soon as a WriteLock is requested no more ReadLocks are granted and the code waiting for the WriteLock is blocked until all the threads with ReadLocks have released them.
The WriteLock can only ever be held by one thread, allow your 'data updates' to appear atomic from the point of view of the consuming parts of your code.
The Lock on the other hand only allows one thread to enter at a time, with no allowance for threads that are simply trying to consume the shared data.
ReaderWriterLockSlim is a new more performant version of ReaderWriterLock with better support for recursion and the ability to have a thread move from a Lock that is essentially a ReadLock to the WriteLock smoothly (UpgradeableReadLock).
ReaderWriterLock/Slim is specifically designed to help you efficiently lock in a multiple consumer/ single producer scenario. Doing so with the lock statement is possible, but not efficient. RWL/S gets the upper hand by being able to aggressively spinlock to acquire the lock. That also helps you avoid lock convoys, a problem with the lock statement where a thread relinquishes its thread quantum when it cannot acquire the lock, making it fall behind because it won't be rescheduled for a while.
It is true that ReaderWriterLockSlim is FASTER than ReaderWriterLock. But the memory consumption by ReaderWriterLockSlim is outright outrageous. Try attaching a memory profiler and see for yourself. I would pick ReaderWriterLock anyday over ReaderWriterLockSlim.
I would suggest looking through http://www.albahari.com/threading/part4.aspx#_Reader_Writer_Locks. It talks about ReaderWriterLockSlim (which you want to use instead of ReaderWriterLock).

Reading same file from multiple threads in C#

I was googling for some advise about this and I found some links. The most obvious was this one but in the end what im wondering is how well my code is implemented.
I have basically two classes. One is the Converter and the other is ConverterThread
I create an instance of this Converter class that has a property ThreadNumber that tells me how many threads should be run at the same time (this is read from user) since this application will be used on multi-cpu systems (physically, like 8 cpu) so it is suppossed that this will speed up the import
The Converter instance reads a file that can range from 100mb to 800mb and each line of this file is a tab-delimitted value record that is imported to another destination like a database.
The ConverterThread class simply runs inside the thread (new Thread(ConverterThread.StartThread)) and has event notification so when its work is done it can notify the Converter class and then I can sum up the progress for all these threads and notify the user (in the GUI for example) about how many of these records have been imported and how many bytes have been read.
It seems, however that I'm having some trouble because I get random errors about the file not being able to be read or that the sum of the progress (percentage) went above 100% which is not possible and I think that happens because threads are not being well managed and probably the information returned by the event is malformed (since it "travels" from one thread to another)
Do you have any advise on better practices of implementation of threads so I can accomplish this?
Thanks in advance.
I read very large files in some of my own code and, I have to tell you, I am skeptical of any claim that adding threads to a read operation would actually improve the overall read performance. In fact, adding threads might actually reduce performance by causing head seeks. It is highly likely that any file operations of this type would be I/O bound, not CPU bound.
Given that the author of the post you referenced never actually provided the 'real' code, his claims that multiple threads will speed up I/O remain untestable by others. Any attempt to improve hard disk read/write performance by adding threads would most certainly be I/O bound, unless he is doing some serious number crunching between reads, or has stumbled upon some happy coincidence having to do with the disk cache, in which case the performance improvement might be unreproduceable on another machine with different hardware characteristics.
Generally, when files of this size are involved, an additional 20% or 30% improvement in performance is not going to matter much, even if it is possible utilizing threads, because such a task would most certainly be considered a background task (not real-time). I use multiple threads for this kind of work, not because it improves read performance on one file, but because multiple files can be processed simultaneously in the background.
Before using threads to do this, I carefully benchmarked the software to see if threads would actually improve overall throughput. The results of the tests (on my development machine) were that using the same number of threads as the number of processor cores produced the maximum possible throughput. But that was processing ONE file per thread.
Multiple threads reading a file at a time is asking for trouble. I would set up a producer consumer model such that the producer read the lines in the file, perhaps into a buffer, and then handed them out to the consumer threads when they complete processing their current work load. It does mean you have a blocking point where the lines are handed out but if processing takes much longer than reading then it shouldn't be that big of a deal. If reading is the slow part then you really don't need multiple consumers anyway.
You should try to just have one thread read the file, since multiple threads will likely be bound by the I/O anyway. Then you can feed the lines into a thread-safe queue from which multiple threads can dequeue lines to parse.
You won't be able to tell the progress of any one thread because that thread has no defined amount of work. However, you should be able to track approximate progress by keeping track of how many items (total) have been added to the queue and how many have been taken out. Obviously as your file reader thread puts more lines into the queue your progress will appear to decrease because more lines are available, but presumably you should be able to fill the queue faster than workers can process the lines.

Categories

Resources