Вот простой код, демонстрирующий, что я пытаюсь сделать
myVar = 1
reader = () ->
getDataFromServer1().then ->
# uses myVar and does stuff according to its value
# returns promise
writer = () ->
getDataFromServer2().then ->
# assigns to myVar
# returns promise
Q.all([reader(), reader(), reader(), writer(), writer(), writer()]).done ->
console.log 'done'
Поэтому у меня одновременно работает несколько потоков. некоторые из них изменяют значение myVar
, а некоторые читают значение и полагаются на него. И я не хочу, чтобы писатель писал, пока пишет другой писатель или читает читатель. Хотя читатели могут читать одновременно. Это похоже на проблему "читатели-писатели".
Я попытался решить эту проблему, определив функцию sharedResource
следующим образом.
sharedResource = (initialValue) ->
readLock = Q.fcall ->
writeLock = Q.fcall ->
value: initialValue
read: (action) ->
newPromise = writeLock.then action
readLock = Q.all([newPromise, readLock]).then -> null
newPromise
write: (action) ->
newPromise = Q.all([readLock, writeLock]).then action
writeLock = Q.all([newPromise, writeLock]).then -> null
newPromise
а затем изменил мой код, чтобы использовать его
myVar = sharedResource 1
reader = () ->
myVar.read ->
# noone is writing to myVar while doing this request:
getDataFromServer1().then (data) ->
# read myVar.value instead of myVar, e.g.
expect(data == myVar.value)
writer = () ->
myVar.write ->
# noone reads or writes myVar while doing this request:
getDataFromServer2().then (data) ->
# change myVar.value instead of myVar, e.g.
myVar.value = data
Q.all([reader(), reader(), reader(), writer(), writer(), writer()]).done ->
console.log 'done'
Это отлично работало, когда у меня был только один sharedResource
. Вот где возникает проблема
myVar1 = sharedResource 1
myVar2 = sharedResource 2
action1 = () ->
myVar1.read ->
myVar2.write ->
getDataFromServer1().then (data) ->
myVar2.value = data + myVar1.value
action2 = () ->
myVar2.read ->
myvar1.write ->
getDataFromServer2().then (data) ->
myVar1.value = data + myVar2.value
Q.all([action1(), action1(), action1(), action2(), action2(), action2()]).done ->
console.log 'done'
Здесь происходит случай тупика. Каждое обещание ожидает разрешения другого. Ни одна из них не решается, и программа останавливается.
Изменить
Я постараюсь объяснить:
На самом деле это код для тестирования моего сервера. Чтобы увидеть, как это работает, когда несколько клиентов отправляют несколько запросов одновременно. Скажем, например, каждый раз, когда action1
отправляет запрос, сервер увеличивает значение, хранящееся в его базе данных. На стороне клиента (код, который вы видите) я также увеличиваю переменную, которая содержит значение, которое, как я ожидаю, будет на сервере. И затем, когда action2
отправляет запрос, сервер отвечает этим значением, и я assert
значение в ответе должно совпадать с моей локальной переменной.
Поэтому я должен получить блокировку, прежде чем отправлять запрос, чтобы убедиться, что action2
не запрашивает переменную во время ее изменения.
Надеюсь, это поможет.
sharedRessource
(изначально у меня были проблемы с этимиaction
, ожидая, что они получат текущее значение в качестве параметра и вернут (обещание) значение для записи; вместо этой.value
манипуляции). Можете ли вы подтвердить, что это все еще передает ваше намерение? - person Bergi   schedule 06.11.2014then(read_is_atomic())
. Единственная неприятная вещь с вашим кодом в том, что ответ не всегда сразу следует за сделанным запросом, он может где-то тормозиться и приходить позже. - person ilyaigpetrov   schedule 04.10.2015