I am trying to synchronize logging to a file in an F Sharp project. Using the lock computational expression I tried to approximate a resource lock, however it seems to not be working.
module regiondeployer.logger open System open System.IO open Microsoft.FSharp.Core open regiondeployer.personalprojectroot type private logginglock = static member public lock = new Object() [<Literal>] let private logfile = personalprojectroot + "log.txt" let public initialize() : unit = use init = File.Create(logfile) () let public logtoconsoleandfile (message:string) : unit = lock logginglock.lock (fun _ -> Console.WriteLine message use logfilestream = File.AppendText(logfile) logfilestream.WriteLine(message) )
System.IO.IOException HResult=0x80070020 Message=The process cannot access the file 'log.txt' because it is being used by another process. Source=mscorlib
What am I missing?
The problem is that your
logginglock.lock is a property with a getter and so a new object is returned each time you access it. As a result, the threads will end up locking different objects and actually access the file concurrently.
If you insist on having the lock object as a field of a static object, then you can define a static field using
static let and then just return the object:
type private logginglock() = static let _lock = new obj() static member public lock = _lock
That said, it would work equally well if you just had the lock object as a global value in a module (as long as it is private to the module). This will likely compile to something very similar as the code above - though there are all sorts of subtleties around locking objects and singletons that I never quite understood...
let private loggingLock = obj()
User contributions licensed under CC BY-SA 3.0