Does a correctly synchronized program still allow data race?(Part I)

后端 未结 3 538
栀梦
栀梦 2020-12-10 17:54

There are two conclusions from JLS:

  • C1: If a program is free of data races, then all executions of the program will appear to be sequentially consistent:
相关标签:
3条回答
  • 2020-12-10 18:26

    http://rsim.cs.illinois.edu/Pubs/popl05.pdf

    The proof seems to go this way:

    Suppose an execution of a correctly synchronized program contains data race, we can find a sequential execution that contains data race, violating the definition of "correctly synchronized program" [C1]

    Therefore the execution must not contain data race. [C3] From there, the execution can be proven to be sequentially consistent. [C2]

    So C3 is true, and it is used to prove C2.

    0 讨论(0)
  • 2020-12-10 18:51

    A good example could be String's hashcode:

    private int hash; // Default to 0
    
    public int hashCode() {
        int h = hash;
        if (h == 0 && count > 0) {
            int off = offset;
            char val[] = value;
            int len = count;
    
            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }
    

    There is a data race here as hash can be written and read by different threads and there is no happens-before relationship (no synchronization).

    However the program is sequentially consistent because it is impossible for a thread to see a hashcode which is not the actual hashcode of the string (when a thread executes the hashcode method, it can either see 0 and recalculate the value, which is deterministic, or it sees a valid value). This works because int writes are atomic.

    EDIT

    This (almost) same code is broken and could return a hashcode of 0:

    public int hashCode() {
        if (hash == 0 && count > 0) { //(1)
            int h = hash;
            int off = offset;
            char val[] = value;
            int len = count;
    
            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return hash; //(2)
    }
    

    as (1) and (2) could be reordered: (1) could read a non null value while (2) would read 0. That can't happen in the first example because the calculation is made on the local variable and the return value is also that local variable, which, by definition, is thread safe.

    EDIT 2

    Regarding your proposition C4, I don't think it is possible:

    A program is correctly synchronized if and only if all sequentially consistent executions are free of data races.

    If a program is correctly synchronized, then all executions of the program will appear to be sequentially consistent (§17.4.3).

    So if a program is correctly synchronized:

    • all the executions appear sequentially consistent.
    • all sequentially consistent executions are free of data races

    So we can conclude that all executions are free of data races and therefore the program is free of data races.

    0 讨论(0)
  • 2020-12-10 18:51

    Race conditions mean to let your program's output depend on who gets at a specific point first. For instance, if you have 2 threads: T1 and T2, if your programs output is X if T1 gets to point P in the program first and the program's output is Y if T2 gets to point P first, then you have a race condition.

    In pseudocode:

     Global variable i initialized to 6;
     Thread 1: 
           aquire(lock l)
                 increment global variable i, i.e. i++;
    
    
     Thread 2: 
           aquire(lock l)
                 double the value of global var i, i.e.: i*=2;
    

    If T1 aquires the lock l firts and T2 second the value of i will be 14 If T2 aquires the lock l firts and T1 second the value of i will be 13

    0 讨论(0)
提交回复
热议问题