Re: ConcurrentLinkedDeque is non-linearizable

Martin Buchholz via Concurrency-interest <[email protected]> Sun, 22 Nov 2020 18:01:18 -0800
Newsgroups gmane.comp.java.jsr.166-concurrency
Message-ID <CA+kOe087gcaYaAXKBOakPCPaG6DkMZR9E=KSo_fLyTMit7w5Kw@mail.gmail.com>
I'm the right guy for linearizability.
I hope to have time to look at this, but not soon.
I filed JDK-8256833 <https://bugs.openjdk.java.net/browse/JDK-8256833>

On Sun, Nov 22, 2020 at 4:51 PM Nikita Koval via Concurrency-interest <
[email protected]> wrote:

> Something got wrong with the formatting, here is the link to the code and
> the test output:
> https://gist.github.com/ndkoval/56ff3b83d2d39e0afd3a08900e1499d4
>
> 23.11.2020, 03:43, "Nikita Koval" <[email protected]>:
>
> Hi,
>
> ConcurrentLinkedDeque was known as non-linearizable in case of concurrent
> operations on the head for a while — that is because the original paper
> with the algorithm was buggy. Nevertheless, there were two attempts about
> ~2 years ago (first <https://bugs.openjdk.java.net/browse/JDK-8196529>,
> second <https://bugs.openjdk.java.net/browse/JDK-8189387>) to make it
> linearizable in Java 9; that was impressive! Unfortunately, I just found a
> new non-linearizable interleaving with Lincheck
> <https://github.com/Kotlin/kotlinx-lincheck> framework.
>
> = Invalid execution results =
> Parallel part:
> | addFirst(10): void [-,1] | addFirst(4): void       |
> | getLast():    4    [1,1] | pollFirst(): 4    [-,1] |
> ---
> values in "[..]" brackets indicate the number of completed operations
> in each of the parallel threads seen at the beginning of the current
> operation
> ---
>
> = The following interleaving leads to the error =
> Parallel part trace:
> |                      | addFirst(4): void
>                                                       |
> |                      | pollFirst()
>                                                       |
> |                      |   first(): Node@1 at
> ConcurrentLinkedDeque.pollFirst(ConcurrentLinkedDeque.java:915)
>        |
> |                      |   item.READ: 4 at
> ConcurrentLinkedDeque.pollFirst(ConcurrentLinkedDeque.java:917)
>           |
> |                      |   prev.READ: null at
> ConcurrentLinkedDeque.pollFirst(ConcurrentLinkedDeque.java:919)
>        |
> |                      |   switch
>                                                        |
> | addFirst(10): void   |
>                                                       |
> | getLast(): 4         |
>                                                       |
> |   thread is finished |
>                                                       |
> |                      |   compareAndSet(Node@1,4,null): true at
> ConcurrentLinkedDeque.pollFirst(ConcurrentLinkedDeque.java:920) |
> |                      |   unlink(Node@1) at
> ConcurrentLinkedDeque.pollFirst(ConcurrentLinkedDeque.java:921)
>         |
> |                      |   result: 4
>                                                       |
> |                      |   thread is finished
>                                                        |
>
> Here is the Lincheck <https://github.com/Kotlin/kotlinx-lincheck> test
> code that reproduces the error:
> class ConcurrentLinkedDequeTest : VerifierState() {    private val d =
> ConcurrentLinkedDeque<Int>()    @Operation fun addFirst(value: Int) = d.addFirst(value)
>    @Operation fun addLast(value: Int) = d.addLast(value)    @Operation fun
> getFirst() = d.peekFirst()    @Operation fun getLast() = d.peekLast()    @Operation
> fun pollFirst() = d.pollFirst()    @Operation fun pollLast() = d.pollLast()
>    override fun extractState() = d.*toList*() *// to determine same
> logical states in LTS construction *    @Test    fun test() =
> ModelCheckingOptions()        .actorsBefore(0)        .actorsAfter(0)
>    .*check*(this::class) }
>
> I hope this will help to make it correct! I would also suggest using
> Lincheck <https://github.com/Kotlin/kotlinx-lincheck> for testing all
> concurrent data structures from the standard concurrency library. It is
> also possible to support blocking operations like Thread.park() (now we
> support blocking operations for Kotlin Coroutines, and the approach can be
> scaled) to test synchronization primitives, like locks or semaphores, as
> well — just let me know if you are interested in this.
>
> Best regards,
> Nikita Koval
>
>
> _______________________________________________
> Concurrency-interest mailing list
> [email protected]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>

_______________________________________________
Concurrency-interest mailing list
[email protected]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest