4

A user is getting an intermittent error "Cannot create file "C:...\Filename.ini". The requested operation cannot be performed on a file with a user-mapped section open."

I haven't been able to find much about this error that helps understand what's going on.

Is TMemIniFile thread-safe?

RobertFrank
  • 7,332
  • 11
  • 53
  • 99

3 Answers3

7

As far as I know TMemIniFile (and any other TCustomIniFile descendants) is not thread-safe. You will need to wrap it into a critical section.

In this link you can find an implementation of a thread-safe TCustomIniFile (theoretically programmed by Peter Below of TeamB though I can not assure it).

There is also a discussion in the Embarcadero forums about the thread-safety of TMemIniFile here. They speak about the C++ version of the component.

You can also find a discussion in MSDN regarding the origin of your error message here. It is a bit long but the general conclussion is that there are 2 exes trying to acces the same file. You can find another discussion on the subject here.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Guillem Vicens
  • 3,936
  • 30
  • 44
  • 2
    I'm sceptical that the internal locking of the thread-safe ini file to which you link is the solution here. It sounds to me more like there are two separate `TMemIniFile` instances trying to write to the same disk file. The code you link to won't help with that. One of the problems with any "is X thread-safe" question is that there are so many different meanings to the term "thread-safe". – David Heffernan May 09 '11 at 20:32
  • @David, you might be right about the separate TMemIniFile instances. The problem, as you state, is that it could be anything: 2 exes, 2 threads, 2 instances on the same thread, etc. Since the OP did not specify that information I added the link just in case it could help him. :) – Guillem Vicens May 10 '11 at 06:05
  • 2
    but your answer doesn't match the symptoms. I know it's got lots up upvotes and an accept but the simple truth is that if internal locking of all methods was the solution the symptoms would be access violations. – David Heffernan May 10 '11 at 06:50
5

First of all, I am assuming that the particular threading configuration that is causing the problem reported is that there are multiple TMemIniFile instances, possibly even in different processes, being saved simultaneously from different threads.

TMemIniFile is not thread-safe. To avoid any race conditions you need to write (pseudo-)code like this:

AcquireLock;
Try
  ReadMemIniFileFromDisk;
  ModifyMemIniFileInMemory;
  WriteMemIniFileToDisk;
Finally
  ReleaseLock;    
End;

It's not enough to lock around just the file operations because then you may lose changes due to a race. You have to lock the entire read/modify/write cycle.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • You could also simply enter the critical section before any access and exit the critical section after any single call or group of calls -- you do NOT have to worry about a race when ONLY ONE thread at a time can ever access it. By definition a race involves two threads operating on an object AT THE SAME TIME. – Warren P May 09 '11 at 23:06
  • @warren the problem here appears to be that there are two instances of TMemIniFile writing to a single file. Internal locking isn't going to do any good. – David Heffernan May 10 '11 at 06:26
  • Ouch. Then that person is confused. I see what you're trying to tell them. But I would think it better to change their code so that they don't instantiate TWO class-wrappers for the same physical resource, and then guard that single instance with a critical section, rather than keep their broken design, and wrap the entire cycle with a global lock. – Warren P May 10 '11 at 13:40
  • There is only one instance of the TMemIniFile instantiated. And only one version of the program running. I have surrounded all access to the object with the locking code you both suggested. The problem persists (but is frustratingly erratic -- and in fact, not reproducible by me...) I'm accessing the object from inside a thread. I'm wondering now if perhaps this object is like the VCL and can't be accessed other than from the main thread. Thanks to both you guys for the help you've given me. – RobertFrank May 10 '11 at 14:07
  • @Robert TMemIniFile doesn't have any window handles and so it can be run out of any thread. What I'm curious about is if you even have multiple threads accessing it. The error does suggest that multiple threads in the system are working on the same file. Is it possible that the issue is caused by your client's anti-virus software? – David Heffernan May 10 '11 at 15:50
  • Hi, David, Thanks so much for following up on this. I'm not sure if I have multiple threads accessing it without metering it, but with the locks in place, hopefully that's not a problem now. There is only one instance of the TMemInifile object.Yes, I suppose this could be anti-virus software on the client's machine. The error doesn't happen all the time, so I don't think that's possible. But, I'll ask him to turn it off. This is one of those frightening, erratic, non-reproducible bugs that panics me! Thank you again. – RobertFrank May 10 '11 at 19:06
  • 1
    @Robert You really need to know what the threads in your app are doing. That you don't know whether or not you have multiple threads accessing the TMemIniFile is a concern. Just applying internal locks will make sure you don't corrupt the data structure, but your program may not be correct. You really need to work this out from the code in my view. – David Heffernan May 10 '11 at 21:36
0

Solution

This error message is caused by a bug in AVG. Apparently in its real-time file-access monitoring mode, AVG opens some files in exclusive mode, preventing others from writing to them.

The fix was to configure AVG to ignore the folder in which this file resides.

Thanks, AVG! Can I have my 2 days of wasted time back now? :-)

Thanks to everyone who answered here.

Tom

RobertFrank
  • 7,332
  • 11
  • 53
  • 99