29.11.2015 Views

The C11 and C++11 Concurrency Model

1ln7yvB

1ln7yvB

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

223<br />

to y, the conditional in the right-h<strong>and</strong> thread is never satisfied, <strong>and</strong> the write it guards<br />

never executes.<br />

Now consider the execution of the client composed with the implementation drawn on<br />

the right above. This execution features load-buffering style relaxed behaviour where each<br />

load reads from a future write on the other thread. In this execution, the library-internal<br />

load of x reads from the client’s write of x, violating safety. This example shows that<br />

for a given client, we cannot establish safety of the implementation as a consequence of<br />

safety of the specification.<br />

It is easy to recognise the client as a potentially unsafe one in the example above<br />

because syntactically it contains an access of the library-internal variable x. <strong>The</strong> same<br />

sort of behaviour can be observed with a client that acts on an address that is decided<br />

dynamically, so that the potential safety violation would not be so easily identified.<br />

In the formulation of the abstraction theorem, this example forces us to require safety<br />

of the client composed with the specification as well as non-interference of the client<br />

composed with the implementation:<br />

<strong>The</strong>orem 21 (Abstraction). Assume that (L 1 ,I 1 ), (L 2 ,I 2 ), (C(L 2 ),I ⊎ I 2 ) are safe,<br />

(C(L 1 ),I⊎I 1 ) is non-interfering <strong>and</strong> (L 1 ,I 1 ) ⊑ (L 2 ,I 2 ). <strong>The</strong>n (C(L 1 ),I⊎I 1 ) is safe <strong>and</strong><br />

client(C(L 1 )(I ⊎I 1 )) ⊆ client(C(L 2 )(I ⊎I 2 )).<br />

<strong>The</strong> unfortunate requirement for non-interference of the implementation in the abstraction<br />

theorem is an important limitation of the C/<strong>C++11</strong> memory model design. It<br />

means that we cannot alleviate the complexity of the relaxed memory model by encapsulating<br />

part of the program in a library <strong>and</strong> then providing a simple specification. <strong>The</strong><br />

programmer will always have to establish that their program is non-interfering according<br />

to the C/<strong>C++11</strong> memory model with the library implementation.<br />

<strong>The</strong> problematic example was a consequence of the presence of self-satisfying conditional<br />

executions: we placed a safety violation in the guarded block on each thread so that<br />

the violations only occurred when self satisfying behaviour was witnessed. If the memory<br />

model forbade self satisfying conditionals (this is difficult to ensure, see Chapter 5 for<br />

details), then the client presented above would be safe. Moreover, we would not need to<br />

check that (C(L 1 ),I ⊎I 1 ) is non-interfering because, after restricting dependency cycles,<br />

any incidence of interference that remained allowed would be a safety violation of either<br />

(L 1 ,I 1 ) or (C(L 2 ),I ⊎ I 2 ). This new restriction in the model would make the language<br />

compositional.<br />

8.3 Abstraction in the Treiber stack<br />

This section presents an overview of the proof of safety, non-interference <strong>and</strong> abstraction<br />

for the specification <strong>and</strong> implementation of the Treiber stack. <strong>The</strong> full proof can be found<br />

in the paper [25]. <strong>The</strong> proof relies on a derived total order,

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!