shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

JSR166 Concurrency mailing list
Hi everyone,

The way "data race" and "correctly synchronized" programs are defined in JMM continue bothering me. It makes completely legit programs producing consistent results with all shared variables declared volatile (see Example2 below) to be "incorrectly synchronized" because data race definition is equally applicable to plain and volatile accesses.

So my question is: shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

----------Explanation of my reasoning
JMM defines data race as follows:
a) Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.
b) When a program [my remark: wrong; not a program, but an execution] contains two conflicting accesses that are not ordered by a happens-before relationship, it is said to contain a data race.
(note how this is equally applicable to plain and volatile accesses.)

JMM defines a correctly synchronized program as follows:
A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.

--------------------Example1
May help with understanding Example2, but you can skip it if Example2 is clear right away.
Let's consider the following program with two concurrently running threads (t1 and t2):

static volatile int s = 0;// w0
t1: r = s;// r
t2: s = 1;// w1

Executions (e1 and e2) with the following two synchronization orders (SO) are allowed by JMM (and there can't be any other SO orders):

SO1: w0, r, w1; which gives notHB(r, w1), notHB(w1, r), r == 0
SO2: w0, w1, r; which gives HB(w1, r), r == 1

Both executions are sequentially consistent by definition because all actions are synchronization actions, hence ordered in a total order SO which is consistent with program order (PO). But e1 has a data race because r and w1 are not ordered by HB. Hence this program is not correctly synchronized by definition despite the only shared variable we have here is volatile s.

--------------------Example2
Now let's change the example a bit by forcing t1 to wait for w1 before making a read r:

static volatile int s = 0 // w0
t1: while (s == 0);// r_i, where i is from [1, k], and k >= 1 and is finite
      r = s;// r
t2: s = 1 // w1

For this program, JMM allows the following execution e1 and a set of analogous executions E2 with the following SO orders respectively (and there can't be any other SO orders):

SO1: w0, w1, r_1, r; which gives HB(w1, r), r == 1
SO2: w0, r_1, ..., w1, ... r_k, r; which gives notHB(r_1, w1), notHB(w1, r_1), HB(w1, r), r == 1

e1 and every execution from E2 are sequentially consistent by definition because all actions are synchronization actions, hence ordered in a total order SO which is consistent with program order (PO). But any execution from E2 has a data race because at least r_1 and w1 are not ordered by HB. Hence this program is not correctly synchronized by definition despite the only shared variable we have here is volatile s, and all the outcomes of the program are the same (r == 1).

Regards,
Valentin

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

JSR166 Concurrency mailing list
Yes, only non-volatile conflicting accesses


It looks like it was agreed that a change was needed, but then what happened?

On Thu, Dec 14, 2017 at 12:49 AM Valentin Kovalenko via Concurrency-interest <[hidden email]> wrote:
Hi everyone,

The way "data race" and "correctly synchronized" programs are defined in JMM continue bothering me. It makes completely legit programs producing consistent results with all shared variables declared volatile (see Example2 below) to be "incorrectly synchronized" because data race definition is equally applicable to plain and volatile accesses.

So my question is: shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

----------Explanation of my reasoning
JMM defines data race as follows:
a) Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.
b) When a program [my remark: wrong; not a program, but an execution] contains two conflicting accesses that are not ordered by a happens-before relationship, it is said to contain a data race.
(note how this is equally applicable to plain and volatile accesses.)

JMM defines a correctly synchronized program as follows:
A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.

--------------------Example1
May help with understanding Example2, but you can skip it if Example2 is clear right away.
Let's consider the following program with two concurrently running threads (t1 and t2):

static volatile int s = 0;// w0
t1: r = s;// r
t2: s = 1;// w1

Executions (e1 and e2) with the following two synchronization orders (SO) are allowed by JMM (and there can't be any other SO orders):

SO1: w0, r, w1; which gives notHB(r, w1), notHB(w1, r), r == 0
SO2: w0, w1, r; which gives HB(w1, r), r == 1

Both executions are sequentially consistent by definition because all actions are synchronization actions, hence ordered in a total order SO which is consistent with program order (PO). But e1 has a data race because r and w1 are not ordered by HB. Hence this program is not correctly synchronized by definition despite the only shared variable we have here is volatile s.

--------------------Example2
Now let's change the example a bit by forcing t1 to wait for w1 before making a read r:

static volatile int s = 0 // w0
t1: while (s == 0);// r_i, where i is from [1, k], and k >= 1 and is finite
      r = s;// r
t2: s = 1 // w1

For this program, JMM allows the following execution e1 and a set of analogous executions E2 with the following SO orders respectively (and there can't be any other SO orders):

SO1: w0, w1, r_1, r; which gives HB(w1, r), r == 1
SO2: w0, r_1, ..., w1, ... r_k, r; which gives notHB(r_1, w1), notHB(w1, r_1), HB(w1, r), r == 1

e1 and every execution from E2 are sequentially consistent by definition because all actions are synchronization actions, hence ordered in a total order SO which is consistent with program order (PO). But any execution from E2 has a data race because at least r_1 and w1 are not ordered by HB. Hence this program is not correctly synchronized by definition despite the only shared variable we have here is volatile s, and all the outcomes of the program are the same (r == 1).

Regards,
Valentin
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

JSR166 Concurrency mailing list
Joe,

Thank you for the reply! It's a relief to know I am not the only one who noticed this.

But if this issue with JMM has been well known for so long (and it is not the only problem) why haven't JMM been ever reworked since Java 1.5? I hoped there were plans to rework JMM for Java 9, but this did not happen even despite the introduction of VarHandle access modes. It feels like such a refactoring will never happen.

Regards,
Valentin



On Thu, Dec 14, 2017 at 1:55 PM, Joe Bowbeer <[hidden email]> wrote:
Yes, only non-volatile conflicting accesses


It looks like it was agreed that a change was needed, but then what happened?

On Thu, Dec 14, 2017 at 12:49 AM Valentin Kovalenko via Concurrency-interest <[hidden email]> wrote:
Hi everyone,

The way "data race" and "correctly synchronized" programs are defined in JMM continue bothering me. It makes completely legit programs producing consistent results with all shared variables declared volatile (see Example2 below) to be "incorrectly synchronized" because data race definition is equally applicable to plain and volatile accesses.

So my question is: shouldn't data race be specified in JMM for non-volatile conflicting accesses only?

----------Explanation of my reasoning
JMM defines data race as follows:
a) Two accesses to (reads of or writes to) the same variable are said to be conflicting if at least one of the accesses is a write.
b) When a program [my remark: wrong; not a program, but an execution] contains two conflicting accesses that are not ordered by a happens-before relationship, it is said to contain a data race.
(note how this is equally applicable to plain and volatile accesses.)

JMM defines a correctly synchronized program as follows:
A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.

--------------------Example1
May help with understanding Example2, but you can skip it if Example2 is clear right away.
Let's consider the following program with two concurrently running threads (t1 and t2):

static volatile int s = 0;// w0
t1: r = s;// r
t2: s = 1;// w1

Executions (e1 and e2) with the following two synchronization orders (SO) are allowed by JMM (and there can't be any other SO orders):

SO1: w0, r, w1; which gives notHB(r, w1), notHB(w1, r), r == 0
SO2: w0, w1, r; which gives HB(w1, r), r == 1

Both executions are sequentially consistent by definition because all actions are synchronization actions, hence ordered in a total order SO which is consistent with program order (PO). But e1 has a data race because r and w1 are not ordered by HB. Hence this program is not correctly synchronized by definition despite the only shared variable we have here is volatile s.

--------------------Example2
Now let's change the example a bit by forcing t1 to wait for w1 before making a read r:

static volatile int s = 0 // w0
t1: while (s == 0);// r_i, where i is from [1, k], and k >= 1 and is finite
      r = s;// r
t2: s = 1 // w1

For this program, JMM allows the following execution e1 and a set of analogous executions E2 with the following SO orders respectively (and there can't be any other SO orders):

SO1: w0, w1, r_1, r; which gives HB(w1, r), r == 1
SO2: w0, r_1, ..., w1, ... r_k, r; which gives notHB(r_1, w1), notHB(w1, r_1), HB(w1, r), r == 1

e1 and every execution from E2 are sequentially consistent by definition because all actions are synchronization actions, hence ordered in a total order SO which is consistent with program order (PO). But any execution from E2 has a data race because at least r_1 and w1 are not ordered by HB. Hence this program is not correctly synchronized by definition despite the only shared variable we have here is volatile s, and all the outcomes of the program are the same (r == 1).

Regards,
Valentin
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


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