nodejs readers/writers concurrency

2019-06-27 13:27发布

Here's some simple code that demonstrates what I'm trying to do

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'

So I have multiple threads running at the same time. some of them change the value of myVar and some read the value and rely on it. And I don't want a writer to write while another writer is writing or a reader is reading. Readers can read at the same time though. This is similar to the Readers–writers problem.

I tried to solve this by defining a sharedResource function as follows

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

and then changed my code to use it

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'

This worked perfectly when I had only one sharedResource. Here's where the problem occurs

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'

Here a case of deadlock happens. Each promise is waiting for the other one to resolve. None of them get resolved and the program stops.

Edit

I'll try my best to explain:

This is actually code to test my server. To see how it performs when multiple clients send multiple requests at the same time. Say for example every time action1 sends a request, the server increments a value stored in it's database. On the client side (the code that you are seeing) I also increment a variable which contains the value I expect to be on the server. And then when action2 sends a request, the server responds with that value and I assert the value in the response to be the same as my local variable.

So I have to get the lock before I send a request to make sure action2 doesn't ask for the variable while it is being changed.

I hope that helps.

0条回答
登录 后发表回答