2015-05-12 39 views
0

我创建了一个名为ticket的可变列表,其中包含Ticket类型。 我也有一个bookSeat函数,它可以模拟预订座位。由于F#列表类型是不可变的,我的bookSeat函数总是返回一个新的,修改后的票据列表副本。如何在多线程中的函数内实现锁定f#

open System 
open System.Threading 

type Ticket = {seat:int; customer:string} 
let mutable tickets = [for n in 1..10 -> {Ticket.seat = n; Ticket.customer = ""}] 
let bookSeat _ = 
    Console.WriteLine("Enter seat number: ") 
    let seatNo = int(Console.ReadLine()) 
    Console.WriteLine("Enter customer name: ") 
    let name = string(Console.ReadLine()) 
    let book seatNo name tickets = 
     tickets |> List.map (fun ticket -> 
      if ticket.seat = seatNo then { ticket with customer = name } 
      else ticket)  
    tickets <- book seatNo name tickets 

我现在想创建两个线程,既调用bookSeat,我想在bookSeat中实现锁定以避免竞争条件。

我想出了这个新的bookSeat功能(仍编程和F#很新,代码可能会显得很菜鸟issh)

let seatNo = ref 0 
let name = ref "" 

let bookSeat _ = 
    Console.WriteLine("Enter seat number: ") 
    seatNo := int(Console.ReadLine()) 
    Console.WriteLine("Enter customer name: ") 
    name:= string(Console.ReadLine().ToString()) 
    let book seatNo name tickets = 
     lock(seatNo,name) (fun()-> tickets |> List.map (fun ticket -> 
      if ticket.seat = seatNo then { ticket with customer = name } 
      else ticket))  
    tickets <- book !seatNo !name tickets 

ThreadPool.QueueUserWorkItem(new WaitCallback(bookSeat)) |> ignore 
ThreadPool.QueueUserWorkItem(new WaitCallback(bookSeat)) |> ignore 
Thread.Sleep(5000) 

代码编译成功,但是当我运行它有一个错误。它输出该紧随其后的错误下面

Enter seat number: 
Enter seat number: 5 
Enter customer name: charles 

Unhandled Exception: System.FormatException: Input string was not in a correct format. 
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer & number, NumberFormatInfo info, Boolean parseDecimal)..... 

错误消息是相当漫长的,将已经张贴图片,但我没有足够的声誉这样做还..

哪有我在我的bookSeat函数中成功实现锁定并在运行时在多个线程中调用它?

+2

此错误有无关锁定。当您尝试将字符串转换为数字时产生。 –

+0

如果仔细观察堆栈跟踪,您会发现代码中的哪个位置会最终引发调用。 – Richard

+0

它只是我还是这种“错误的建筑”?认为使用函数式编程思想的一部分是为了避免这样的问题... 只是放弃锁定并使用代理/邮箱的某些变体,会不会更好?那么应用“先到先得”,并且因为只有一个人在任何时候访问该列表,所以不需要锁定。 –

回答

0

你的两个线程正在竞争控制台;可能输入“charles”被执行seatNo := int(Console.ReadLine()赋值的线程占用。

我同意使用代理/ MailboxProcessors的意见,但如果你想用锁来做到这一点,锁定提示输入序列:

let bookSeat _ = 
    lock (seatNo) (fun _ -> 
    Console.WriteLine("Enter seat number: ") 
    seatNo := int(Console.ReadLine()) 
) 
    lock (name) (fun _ -> 
    Console.WriteLine("Enter customer name: ") 
    name:= string(Console.ReadLine().ToString() 
) 
    ...