www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - synchronized vs. C volatile

reply SK <sk metrokings.com> writes:
Does 'synchronized' mean the exact same thing as the C 'volatile'
qualifier when applied to basic types?
As in:
synchronized int x;
Aug 08 2010
next sibling parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from SK (sk metrokings.com)'s article
 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

They're completely different. synchronized is basically a scoped mutex and applies to a statement, not a variable declaration. I have no idea what your example does, but it probably shouldn't even compile. Volatile just prevents certain compiler optimizations that can interfere with updates to a variable from other hardware besides the CPU and is useful for things like device drivers.
Aug 09 2010
next sibling parent reply Sean Kelly <sean invisibleduck.org> writes:
SK Wrote:

 On Mon, Aug 9, 2010 at 6:25 AM, dsimcha <dsimcha yahoo.com> wrote:
 == Quote from SK (sk metrokings.com)'s article
 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

They're completely different.  synchronized is basically a scoped mutex and applies to a statement, not a variable declaration.  I have no idea what your example does, but it probably shouldn't even compile.  Volatile just prevents certain compiler optimizations that can interfere with updates to a variable from other hardware besides the CPU and is useful for things like device drivers.

Sounds right to me too. But the compiler warns about deprecated 'volatile'. Is the warning a mistake? Volatile has an important place in a systems language and I'd rather not mess with tradition here.

volatile is present in D1 but was deprecated in D2 in favor of shared. I actually liked D1 volatile, but I think I was among the few. In short, D1 volatile did the bare minimum to ensure that correct multithreaded code could be implemented by constraining compiler optimizations across volatile statement boundaries. For correct synchronized behavior, memory barriers still might have to be added however. As an alternative, Walter has stated before that it is invalid for the compiler to optimize across asm statement boundaries as well, so a similar effect can often be had by writing inline asm. Similar requirements apply to shared variables as well, which can be modified either in-language or by importing std.concurrency or core.atomic to perform more complex atomic ops. Both of these are likely to insert memory barriers when shared variables are accessed however.
Aug 09 2010
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Sean Kelly (sean invisibleduck.org)'s article
 SK Wrote:
 On Mon, Aug 9, 2010 at 6:25 AM, dsimcha <dsimcha yahoo.com> wrote:
 == Quote from SK (sk metrokings.com)'s article
 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

They're completely different.  synchronized is basically a scoped mutex and applies to a statement, not a variable declaration.  I have no idea what your example does, but it probably shouldn't even compile.  Volatile just prevents certain compiler optimizations that can interfere with updates to a variable



 other hardware besides the CPU and is useful for things like device drivers.

Sounds right to me too. But the compiler warns about deprecated 'volatile'. Is the warning a mistake? Volatile has an important place in a systems language and I'd rather not mess with tradition here.


volatile did the bare minimum to ensure that correct multithreaded code could be implemented by constraining compiler optimizations across volatile statement boundaries. For correct synchronized behavior, memory barriers still might have to be added however.
 As an alternative, Walter has stated before that it is invalid for the compiler

be had by writing inline asm. Similar requirements apply to shared variables as well, which can be modified either in-language or by importing std.concurrency or core.atomic to perform more complex atomic ops. Both of these are likely to insert memory barriers when shared variables are accessed however. Does this include even empty asm statements, for example: int i; // Volatile. // Do stuff. asm {} // No code motion across this. i++; asm {} // No code motion across this. // Do more stuff.
Aug 09 2010
parent Sean Kelly <sean invisibleduck.org> writes:
dsimcha Wrote:

 == Quote from Sean Kelly (sean invisibleduck.org)'s article
 As an alternative, Walter has stated before that it is invalid for the compiler

be had by writing inline asm. Similar requirements apply to shared variables as well, which can be modified either in-language or by importing std.concurrency or core.atomic to perform more complex atomic ops. Both of these are likely to insert memory barriers when shared variables are accessed however. Does this include even empty asm statements, for example: int i; // Volatile. // Do stuff. asm {} // No code motion across this. i++; asm {} // No code motion across this. // Do more stuff.

I wondered the same thing when writing my response. Personally, I wouldn't consider this safe because the compiler can trivially determine that the block is empty and make it vanish. To be safe I think you'd at least have to put a NOP in there, so I guess you could do something like: property void optbar() { asm { naked; NOP; } } void volatile(lazy void exp) { optbar; exp(); optbar; } int x; /*volatile*/ int y; volatile(x = y);
Aug 09 2010
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
SK wrote:

 On Mon, Aug 9, 2010 at 6:25 AM, dsimcha <dsimcha yahoo.com> wrote:
 == Quote from SK (sk metrokings.com)'s article
 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

They're completely different. synchronized is basically a scoped mutex and applies to a statement, not a variable declaration. I have no idea what your example does, but it probably shouldn't even compile. Volatile just prevents certain compiler optimizations that can interfere with updates to a variable from other hardware besides the CPU and is useful for things like device drivers.

Sounds right to me too. But the compiler warns about deprecated 'volatile'. Is the warning a mistake? Volatile has an important place in a systems language and I'd rather not mess with tradition here. $ cat main.d int main() { volatile int x = 1; synchronized int y = 1; return 0; } $ dmd -w -wi main.d main.d(4): volatile statements deprecated; used synchronized statements instead

I'm not an expert on this, but if I am not mistaken the shared type qualifier will handle the barriers, require atomic ops and prevent reordering compiler optimizations so it looks like this one will take care of what volatile used to do, right?
Aug 09 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
SK:
 asm() hacks to fake volatile are too embarrassing to consider in a
 promising new systems language!

D2 has a good chance to become a system language, but it isn't yet. The main problems don't come from missing features that are easy to add later, the problems are in the possible presence of suboptimally designed features :-) Bye, bearophile
Aug 10 2010
prev sibling parent Sean Kelly <sean invisibleduck.org> writes:
Steven Schveighoffer Wrote:
 
 As of now, D supports only x86.  I think it has nestled itself into a  
 place where it needs to make tremendous assumptions about the processor  
 and OS.  For example, the OS *must* support thread local storage.

It doesn't have to be an OS-level thing. In D, TLS on OSX allocates its storage dynamically within library code because OSX doesn't support __thread yet.
Aug 10 2010
prev sibling next sibling parent SK <sk metrokings.com> writes:
On Mon, Aug 9, 2010 at 6:25 AM, dsimcha <dsimcha yahoo.com> wrote:
 =3D=3D Quote from SK (sk metrokings.com)'s article
 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

They're completely different. =A0synchronized is basically a scoped mutex=

 applies to a statement, not a variable declaration. =A0I have no idea wha=

 example does, but it probably shouldn't even compile. =A0Volatile just pr=

 certain compiler optimizations that can interfere with updates to a varia=

 other hardware besides the CPU and is useful for things like device drive=


Sounds right to me too. But the compiler warns about deprecated 'volatile'. Is the warning a mistake? Volatile has an important place in a systems language and I'd rather not mess with tradition here. $ cat main.d int main() { volatile int x =3D 1; synchronized int y =3D 1; return 0; } $ dmd -w -wi main.d main.d(4): volatile statements deprecated; used synchronized statements ins= tead
Aug 09 2010
prev sibling next sibling parent reply BCS <none anon.com> writes:
Hello SK,

 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

I'm reasonably sure that it doesn't. I think synchronized invokes a mutex for access and C's volatile just suppresses some optimizations. -- ... <IXOYE><
Aug 09 2010
parent reply Sean Kelly <sean invisibleduck.org> writes:
SK Wrote:
 
 Andrei's book does not list volatile as a keyword in D.  I'm at a loss
 unless 'synchronized' performs double duty as volatile.  For example,
 device status registers are "const volatile" in C/C++.  The compiler
 disallows writes and does not optimize away reads.   Mutexes are
 irrelevant and for that matter the processor may not (and need not)
 even support atomic instructions.

So you're one of the few people who actually use C volatile as intended, huh? :-) I think right now your best bet is to use inline asm, or call out to a function written in assembly if you're targeting something other than x86. As I said in my other post, the compiler won't optimize away ask blocks, nor will it optimize across them. Walter has stated that it's incorrect behavior for a compiler to do so. GDC or LDC might however, I really couldn't say.
Aug 09 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Sean Kelly:
As I said in my other post, the compiler won't optimize away ask blocks, nor
will it optimize across them.  Walter has stated that it's incorrect behavior
for a compiler to do so.  GDC or LDC might however, I really couldn't say.<

In LDC there are two ways to inline asm statements and functions that contain them, but both are explicit, so on default it acts as DMD (but I don't think this is well tested). Bye, bearophile
Aug 09 2010
prev sibling next sibling parent SK <sk metrokings.com> writes:
On Mon, Aug 9, 2010 at 7:29 AM, BCS <none anon.com> wrote:
 Hello SK,

 Does 'synchronized' mean the exact same thing as the C 'volatile'
 qualifier when applied to basic types?
 As in:
 synchronized int x;

I'm reasonably sure that it doesn't. I think synchronized invokes a mutex for access and C's volatile just suppresses some optimizations. -- ... <IXOYE><

Andrei's book does not list volatile as a keyword in D. I'm at a loss unless 'synchronized' performs double duty as volatile. For example, device status registers are "const volatile" in C/C++. The compiler disallows writes and does not optimize away reads. Mutexes are irrelevant and for that matter the processor may not (and need not) even support atomic instructions. -steve
Aug 09 2010
prev sibling next sibling parent reply SK <sk metrokings.com> writes:
On Mon, Aug 9, 2010 at 9:55 AM, Lutger <lutger.blijdestijn gmail.com> wrote:
 I'm not an expert on this, but if I am not mistaken the shared type qualifier
 will handle the barriers, require atomic ops and prevent reordering compiler
 optimizations so it looks like this one will take care of what volatile used to
 do, right?

Right, shared sounds better. However, atomics must not sneak in: * Many processors do not support atomics Even with processor support, * Many device interconnects do not support atomic transactions Even with interconnect support, * Many devices do not support atomic transactions and will just generate a bus error So long as code does not attempt a read-modify-write operation, shared has the opportunity to do the right thing, namely implement volatile semantics. Cases with volatile read-modify-write would have to be split -- awkward, but maybe ok? asm() hacks to fake volatile are too embarrassing to consider in a promising new systems language! -steve
Aug 09 2010
parent reply Kagamin <spam here.lot> writes:
SK Wrote:

 So long as code does not attempt a read-modify-write operation, shared
 has the opportunity to do the right thing, namely implement volatile
 semantics.  Cases with volatile read-modify-write would have to be
 split -- awkward, but maybe ok?

D provides good behavior by default (for most common cases). If you want alternative behavior, you can still implement it by, say, casting. Not D is more targeted for user application development. For kernel development compiler should be modified (gcc is, for example).
Aug 11 2010
parent Kagamin <spam here.lot> writes:
Kagamin Wrote:

 Not D is more targeted for user application development.

*Now
Aug 11 2010
prev sibling next sibling parent SK <sk metrokings.com> writes:
--0016e64c1800de46c2048d702ddd
Content-Type: text/plain; charset=ISO-8859-1

On Mon, Aug 9, 2010 at 9:55 AM, Lutger <lutger.blijdestijn gmail.com> wrote:
 I'm not an expert on this, but if I am not mistaken the shared type

 will handle the barriers, require atomic ops and prevent reordering

 optimizations so it looks like this one will take care of what volatile

 do, right?

Seems the latest dmd in svn hasn't implemented shared atomics yet anyway. If it had, we'd see a lock prefix in use. $ cat main.d shared int x = 1; int main() { x = x + 1; ++x; return 0; } $ dmd -O -w -wi main.d $ objdump -d main.o main.o: file format elf32-i386 Disassembly of section .text: 00000000 <.text>: 0: c3 ret 1: 60 pusha 2: b8 14 00 00 00 mov $0x14,%eax 7: b9 00 00 00 00 mov $0x0,%ecx c: 8b 11 mov (%ecx),%edx e: 89 10 mov %edx,(%eax) 10: 89 01 mov %eax,(%ecx) 12: 61 popa 13: c3 ret Disassembly of section .text._Dmain: 00000000 <_Dmain>: 0: 55 push %ebp 1: a1 00 00 00 00 mov 0x0,%eax 6: 40 inc %eax 7: a3 00 00 00 00 mov %eax,0x0 c: 8b ec mov %esp,%ebp e: 31 c0 xor %eax,%eax 10: 83 05 00 00 00 00 01 addl $0x1,0x0 17: 5d pop %ebp 18: c3 ret --0016e64c1800de46c2048d702ddd Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable On Mon, Aug 9, 2010 at 9:55 AM, Lutger &lt;<a href=3D"mailto:lutger.blijdes= tijn gmail.com" target=3D"_blank">lutger.blijdestijn gmail.com</a>&gt; wrot= e:<br>&gt;<br>&gt; I&#39;m not an expert on this, but if I am not mistaken = the shared type qualifier<br> &gt; will handle the barriers, require atomic ops and prevent reordering co= mpiler<br>&gt; optimizations so it looks like this one will take care of wh= at volatile used to<br>&gt; do, right?<br>&gt;<br>&gt;<br><br>Seems the lat= est dmd in svn hasn&#39;t implemented shared atomics yet anyway.=A0 If it h= ad, we&#39;d see a lock prefix in use.<br> <br><span style=3D"font-family: courier new,monospace;">$ cat main.d</span>= <br style=3D"font-family: courier new,monospace;"><span style=3D"font-famil= y: courier new,monospace;">shared int x =3D 1;</span><br style=3D"font-fami= ly: courier new,monospace;"> <span style=3D"font-family: courier new,monospace;">int main()</span><br st= yle=3D"font-family: courier new,monospace;"><span style=3D"font-family: cou= rier new,monospace;">{</span><br style=3D"font-family: courier new,monospac= e;"> <span style=3D"font-family: courier new,monospace;">=A0x =3D x + 1;</span><= br style=3D"font-family: courier new,monospace;"><span style=3D"font-family= : courier new,monospace;">=A0++x;</span><br style=3D"font-family: courier n= ew,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0return 0;</span><br = style=3D"font-family: courier new,monospace;"><span style=3D"font-family: c= ourier new,monospace;">}</span><br style=3D"font-family: courier new,monosp= ace;"> <span style=3D"font-family: courier new,monospace;">$ dmd -O -w -wi main.d<= /span><br style=3D"font-family: courier new,monospace;"><span style=3D"font= -family: courier new,monospace;">$ objdump -d main.o</span><br style=3D"fon= t-family: courier new,monospace;"> <br style=3D"font-family: courier new,monospace;"><span style=3D"font-famil= y: courier new,monospace;">main.o:=A0=A0=A0=A0 file format elf32-i386</span=
<br style=3D"font-family: courier new,monospace;"><br style=3D"font-family=

<br style=3D"font-family: courier new,monospace;"><span style=3D"font-famil= y: courier new,monospace;">Disassembly of section .text:</span><br style=3D= "font-family: courier new,monospace;"><br style=3D"font-family: courier new= ,monospace;"> <span style=3D"font-family: courier new,monospace;">00000000 &lt;.text&gt;:= </span><br style=3D"font-family: courier new,monospace;"><span style=3D"fon= t-family: courier new,monospace;">=A0=A0 0:=A0=A0 c3=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ret=A0=A0=A0 </span><br style=3D= "font-family: courier new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0=A0 1:=A0=A0 60=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 pusha=A0 </spa= n><br style=3D"font-family: courier new,monospace;"><span style=3D"font-fam= ily: courier new,monospace;">=A0=A0 2:=A0=A0 b8 14 00 00 00=A0=A0=A0=A0=A0= =A0=A0=A0=A0 mov=A0=A0=A0 $0x14,%eax</span><br style=3D"font-family: courie= r new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0=A0 7:=A0=A0 b9 00 0= 0 00 00=A0=A0=A0=A0=A0=A0=A0=A0=A0 mov=A0=A0=A0 $0x0,%ecx</span><br style= =3D"font-family: courier new,monospace;"><span style=3D"font-family: courie= r new,monospace;">=A0=A0 c:=A0=A0 8b 11=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 mov=A0=A0=A0 (%ecx),%edx</span><br style=3D"font-family:= courier new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0=A0 e:=A0=A0 89 10= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 mov=A0=A0=A0 %edx,(%= eax)</span><br style=3D"font-family: courier new,monospace;"><span style=3D= "font-family: courier new,monospace;">=A0 10:=A0=A0 89 01=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 mov=A0=A0=A0 %eax,(%ecx)</span><br sty= le=3D"font-family: courier new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0 12:=A0=A0 61=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 popa=A0=A0 </span=
<br style=3D"font-family: courier new,monospace;"><span style=3D"font-fami=

=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ret=A0=A0=A0 </span><br style=3D"font-fam= ily: courier new,monospace;"> <br style=3D"font-family: courier new,monospace;"><span style=3D"font-famil= y: courier new,monospace;">Disassembly of section .text._Dmain:</span><br s= tyle=3D"font-family: courier new,monospace;"><br style=3D"font-family: cour= ier new,monospace;"> <span style=3D"font-family: courier new,monospace;">00000000 &lt;_Dmain&gt;= :</span><br style=3D"font-family: courier new,monospace;"><span style=3D"fo= nt-family: courier new,monospace;">=A0=A0 0:=A0=A0 55=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 push=A0=A0 %ebp</span><br style= =3D"font-family: courier new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0=A0 1:=A0=A0 a1 00 0= 0 00 00=A0=A0=A0=A0=A0=A0=A0=A0=A0 mov=A0=A0=A0 0x0,%eax</span><br style=3D= "font-family: courier new,monospace;"><span style=3D"font-family: courier n= ew,monospace;">=A0=A0 6:=A0=A0 40=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 inc=A0=A0=A0 %eax</span><br style=3D"font-family: cou= rier new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0=A0 7:=A0=A0 a3 00 0= 0 00 00=A0=A0=A0=A0=A0=A0=A0=A0=A0 mov=A0=A0=A0 %eax,0x0</span><br style=3D= "font-family: courier new,monospace;"><span style=3D"font-family: courier n= ew,monospace;">=A0=A0 c:=A0=A0 8b ec=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0 mov=A0=A0=A0 %esp,%ebp</span><br style=3D"font-family: cour= ier new,monospace;"> <span style=3D"font-family: courier new,monospace;">=A0=A0 e:=A0=A0 31 c0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 xor=A0=A0=A0 %eax,%e= ax</span><br style=3D"font-family: courier new,monospace;"><span style=3D"f= ont-family: courier new,monospace;">=A0 10:=A0=A0 83 05 00 00 00 00 01=A0= =A0=A0 addl=A0=A0 $0x1,0x0</span><br style=3D"font-family: courier new,mono= space;"> <span style=3D"font-family: courier new,monospace;">=A0 17:=A0=A0 5d=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 pop=A0=A0=A0 %ebp= </span><br style=3D"font-family: courier new,monospace;"><span style=3D"fon= t-family: courier new,monospace;">=A0 18:=A0=A0 c3=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 ret</span><br> --0016e64c1800de46c2048d702ddd--
Aug 09 2010
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 09 Aug 2010 20:09:54 -0400, SK <sk metrokings.com> wrote:

 On Mon, Aug 9, 2010 at 9:55 AM, Lutger <lutger.blijdestijn gmail.com>  
 wrote:
 I'm not an expert on this, but if I am not mistaken the shared type  
 qualifier
 will handle the barriers, require atomic ops and prevent reordering  
 compiler
 optimizations so it looks like this one will take care of what volatile  
 used to
 do, right?

Right, shared sounds better. However, atomics must not sneak in: * Many processors do not support atomics Even with processor support, * Many device interconnects do not support atomic transactions Even with interconnect support, * Many devices do not support atomic transactions and will just generate a bus error

As of now, D supports only x86. I think it has nestled itself into a place where it needs to make tremendous assumptions about the processor and OS. For example, the OS *must* support thread local storage. Many embedded processors are not even close to as complex as x86, so you may not need to worry about a lot of the things D takes care of. I'd expect a version of D for embedded systems may be a different language altogether.
 asm() hacks to fake volatile are too embarrassing to consider in a
 promising new systems language!

In the land D is targeting -- namely the application/system space, not the kernel space -- volatile is not exactly needed much. I think shared is fine for thread-safe access to variables. Registers aren't really used in user-land code. I don't pretend to understand why Walter decided volatile wasn't adequate, but there were some discussions a while back.
 -steve

Hey, that's my sig! I guess you can have it as long as you always make it lower case. -Steve :)
Aug 10 2010