0

I have a multi thread application. My problem is that sometimes I get an error like the program cannot access to a file as it is been used by something else (other part of the application).

Right now what I did is catch the exception and repeat the task after a 100ms delay.

It is working as the application does not open the files so often and it is open the files just for a short period.

Though I am not happy with that solution as it is ugly, and it still can go wrong.

Are there any good ways to sort out that problem? If there are not any easy answer and you need more information about the application(what files, why I might access in the same time) I can answer, I just try to keep the question simple, and generic.

Regards Daniel

EDIT:

I made up something fast, what do you guys think about that solution, it is not the most generic one, but had no better idea just now:

When the program try to write into the file check if the it is used or not. If it is used collect a data in the memory, as soon as the application want to write in to the file again and the file is free insert in all of the data.

It still not the best, but it might give some more ideas.

Daniel
  • 383
  • 1
  • 5
  • 20
  • How do you open the files? Can you use the `FileShare.ReadWrite` parameter to the `FileStream` constructor? See http://msdn.microsoft.com/en-us/library/5h0z48dh.aspx – Gabe May 28 '13 at 15:13
  • related question http://stackoverflow.com/questions/3808474/whats-the-right-pattern-for-waiting-on-a-file-lock-to-be-released – PeskyGnat May 28 '13 at 15:14
  • @Gabe I am using StreamWriter. When I read the file I need to read out all of the data till the end, when I insert I insert data to the end. Wont it get doggy(losing data) if I share the file? – Daniel May 28 '13 at 15:21

1 Answers1

3

Since your application is both reading and writing the file, all you need to do is keep track of which files your application is using. Keep a dictionary of R/W locks keyed by file name. When you go to access a file, take out the appropriate lock.

Here's how you might code it:

Dictionary<string, ReaderWriterLockSlim> lockDict = new Dictionary<string, ReaderWriterLockSlim>();

ReaderWriterLockSlim LockFile(string filename, bool readOnly)
{
    var fullPath = System.IO.Path.GetFullPath(filename);
    ReaderWriterLockSlim myLock;
    // lock the dictionary while we're accessing it
    lock (lockDict)
    {
        if (!lockDict.TryGetValue(fullPath, out myLock))
        {
            myLock = new ReaderWriterLockSlim();
            lockDict[fullPath] = myLock;
        }
    }
    // only block on the file lock once the dictionary is unlocked
    if (readOnly)
        myLock.EnterReadLock();
    else
        myLock.EnterWriteLock();
    // file is now "locked", so caller can proceed with read/write, then unlock
    return myLock;
}

And you might use it like this:

// block until we're not using the file anymore
var myLock = LockFile(filename, readOnly: false);
try
{
    using (var file = new StreamWriter(filename))
    {
    ...
    }
}
finally
{
    myLock.ExitWriteLock();
}
Gabe
  • 84,912
  • 12
  • 139
  • 238
  • A `try-finally` block may work best for the usage example for ensuring the write lock is released. – Scott Chamberlain May 29 '13 at 03:21
  • @Scott: You don't want to risk exiting the file lock before the file is closed, so I didn't implement it with a `finally`. – Gabe May 29 '13 at 03:53
  • If the try encompasses the using block the file lock will be released before the finally fires. `var myLock = ...; try { using (var file = new StreamWriter(filename)) { ... } } finally { myLock.ExitWriteLock(); }` or do I have a incorrect assumption somewhere? – Scott Chamberlain May 29 '13 at 04:04
  • Now if you want to be [super fancy](http://msdn.microsoft.com/en-us/library/gg712738.aspx) you can replace your storage dictionary with a `Dictionary>` :) – Scott Chamberlain May 29 '13 at 04:19
  • @Scott: While you're at it, why not go for a `ConcurrentDictionary` and eliminate the unnecessary locking? – Gabe May 29 '13 at 04:31
  • So Basically the best solution is to lock the file, and make wait the method which want to access if it is locked. If I put a readOnly lock on a file, and I am writing it in the same time, will the "reading" function able to read out the data which is added by the writer function which set the readOnly lock? – Daniel May 29 '13 at 08:08
  • If you put a read-only lock on a file, you *can't* write to it at the same time. The read-only lock will wait until the writer is done, or the writer will wait until the read-only lock is done. – Gabe May 29 '13 at 12:38
  • Oh OK, I do not know why it was in my head that the lock is bound to the process not to the file:p silly me:P Thank you for your help, I guess I just mark your answer as a solution, as it seems to be a good way to do it. – Daniel May 29 '13 at 13:24