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