Ошибка System.FormatException при многопоточности - PullRequest
0 голосов
/ 24 апреля 2020

Мне нужно создать два потока для небольшого проекта F #, который реализует блокировку, чтобы избежать состояния гонки. (Я отсканировал StackOverflow для ответов безрезультатно, поэтому этот пост)

Вот код:

let bookFood _ =
    Console.WriteLine("Enter amount of grocery bags: ")
    let groceryBags = int(Console.ReadLine())
    Console.WriteLine("Enter customer name: ")
    let name = string(Console.ReadLine().ToString())
    let book bags name orders = 
        lock(bags,name) (fun()-> orders |> List.map (fun order ->
            if order.bags = bags then { order with customer = name }
            else order ))    
    orders <- book groceryBags name orders

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

Проблема в том, что при запуске этого кода происходит следующее:

Мне предлагается ввести количество продуктовых сумок дважды (как должно быть?), Потому что я дважды вызываю функцию bookFood, верно?)

Затем мне предлагается ввести имя клиента, как только я ввожу это, приложение вылетает со следующей ошибкой: System.FormatException выдано, строка ввода не в правильном формате.

Я всюду искал решение, но сейчас обращаюсь за помощью.

Уточнение:

Как мне решить эту проблему? Это потому, что я неправильно закодировал блокировку или неправильно создаю два потока? Он прекрасно работает, когда я вызываю метод bookFood только один раз, но задача требует, чтобы я создал два потока и использовал блокировку, чтобы избежать состояния гонки, и именно тогда я получаю эту ошибку.

Большое спасибо активному сообществу F #, которое помогает, вы знаете, кто вы есть.

1 Ответ

3 голосов
/ 24 апреля 2020

Если вы используете отладчик, вы должны найти точку, в которой он ломается:

let groceryBags = int(Console.ReadLine())

Помните, как вам «предлагают ввести количество продуктовых сумок дважды» - это потому, что вы Вы выполняете вызов на ReadLine() в двух потоках.

Когда вы введете количество сумок, следующий вызов ReadLine будет равен "количеству сумок" другого метода book, и вы введете имя там, которое не может быть преобразовано в int, поэтому оно выдает исключение, говорящее, что оно не в правильном формате.

Если вы ввели только цифры, в том числе и для имени, вы не должны не понимаю эту ошибку.

  1. Console функции не являются поточно-ориентированными, и вы действительно не должны использовать его таким образом.
  2. Используйте Int32.TryParse, чтобы увидеть, соответствует ли ваша строка формату вместо того, чтобы генерировать исключение, когда этого не происходит.
  3. Для блокировки необходим общий объект между всеми вашими потоками. Вы создаете новый объект кортежа в каждом замке - который ничего не будет делать. Попробуйте заблокировать специально созданный объект блокировки, подойдет let gate = new Object().
...