I am having issues with multiple threads in a c# application trying to read and/or wri开发者_Python百科te to a log file. Occasionally an exception is thrown, and I am suspecting this is due to collisions. Is there a good way to guarantee exclusive access for each thread when it opens the files?
You can fix that with locking a sync object in the logger class. Something like this would work and is what I do for my logger code.
private static readonly object syncObject = new object();
// .. when ready to write to a file in a method
lock(syncObject)
{
// write to file here,
// no other thread is able to write to the file while this is locked
}
This synchronizes the file writes and guarantees that you won't have write "collisions".
Locking is probably the more suitable way here. If performance is critical, you could resort to some kind of queuing of the log messages with e.g. a ConcurrentQueue<T>
, which should be quite optimized for concurrent read/write, together with a producer consumer pattern.
The simplest thing to do is use a logging framework, such as log4net, that is thread-safe out of the box.
If for some reason you cannot use a logging framework, you will have to use one of the thread-syncing methods mentioned above and manage access yourself.
Filesystems generally have built-in locking systems, so unless your threads are all using the same Stream
object then you should be fine. If they're not, set up your own lock for each file access (normally concurrent reads can be done but if you don't want to use a different stream for each one it is impossible):
lock(streamObject) {
// access the file here
}
I would recommend you create a different stream for each access or each thread, however. If you are using different streams, I don't think that's your problem...
Note that this doesn't count as creating a new stream:
using(StreamReader sr = new StreamReader(theBaseStream)) {
...
because it still uses the same base Stream
object.
What about a thread only for logging that communicates through a concurrent queue and slim wait events?
Then you can write from multiple threads in a non-blocking way, good for multiprocessor systems.
You just enqueue a new log object or better, a struct or just a string and the thread that receive queue events can then print\write\save\manipulate the received messages in a totally asynchronous way.
You can read files from that queue with messages to that thread too (something like invokes or sendmessage).
You can use an object to lock the file.
Write your file access code within lock(object) { your file access code ... }
so that it will not be executed simultaneously.
精彩评论