digitalmars.D - Synchronized Classes and Struct Members
- Andrew Wiley <wiley.andrew.j gmail.com> Oct 24 2011
- Benjamin Thaut <code benjamin-thaut.de> Oct 24 2011
- Timon Gehr <timon.gehr gmx.ch> Oct 25 2011
- Timon Gehr <timon.gehr gmx.ch> Oct 25 2011
- simendsjo <simendsjo gmail.com> Oct 25 2011
- Timon Gehr <timon.gehr gmx.ch> Oct 25 2011
- Andrew Wiley <wiley.andrew.j gmail.com> Oct 24 2011
- Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> Oct 25 2011
- Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> Oct 25 2011
- Andrew Wiley <wiley.andrew.j gmail.com> Oct 25 2011
- Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> Oct 25 2011
- Andrew Wiley <wiley.andrew.j gmail.com> Oct 25 2011
--90e6ba6e8298804a8104b019596e
Content-Type: text/plain; charset=ISO-8859-1
Geez, I try to write some multithreaded code and I just keep hitting these:
--------
module test3;
struct SomeData {
int i;
int iPlus2() {
return i + 2;
}
}
synchronized class Bob {
private:
SomeData _dat;
public:
this() {
_dat.i = 3;
}
property
int i() {
return _dat.iPlus2(); // test3.d(22): Error: function test3.SomeData.iPlus2
() is not callable using argument types () shared
}
}
--------
This seems like it should be legal because SomeData is a value type.
Accessing _dat.i directly is legal, and _dat can't possibly be shared. If
I'm understanding things correctly, transitive shared shouldn't apply to
value types like this, so the type of "this" when calling iPlus2 should just
be SomeData.
--90e6ba6e8298804a8104b019596e
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Geez, I try to write some multithreaded code and I just keep hitting these:=
<div>--------<br><div><div>module test3;</div><div><br></div><div>struct So=
meData {</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"=
</span>int i;</div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span></div=
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>int =
e"> </span>return i + 2;</div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</di=
v><div>}</div><div><br></div><div>synchronized class Bob {</div><div>privat=
e:</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </sp=
an>SomeData _dat;</div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span></div=
<div>public:</div><div><span class=3D"Apple-tab-span" style=3D"white-space=
ite-space:pre"> </span>_dat.i =3D 3;</div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</di=
v><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span></d=
iv><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span> p=
roperty</div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>int i=
() {</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> <=
/span>return _dat.iPlus2(); //=A0<span style=3D"background-color: transpare=
nt; ">test3.d(22): Error: function test3.SomeData.iPlus2 () is not callable=
using argu</span><span style=3D"background-color: transparent; ">ment type=
s () shared</span></div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</di=
v><div>}</div></div><div>--------</div></div><div><br></div><div>This seems=
like it should be legal because SomeData is a value type. Accessing _dat.i=
directly is legal, and _dat can't possibly be shared. If I'm under=
standing things correctly, transitive shared shouldn't apply to value t=
ypes like this, so the type of "this" when calling iPlus2 should =
just be SomeData.</div>
--90e6ba6e8298804a8104b019596e--
Oct 24 2011
Am 25.10.2011 08:06, schrieb Andrew Wiley:Geez, I try to write some multithreaded code and I just keep hitting these: -------- module test3; struct SomeData { int i; int iPlus2() { return i + 2; } } synchronized class Bob { private: SomeData _dat; public: this() { _dat.i = 3; } property int i() { return _dat.iPlus2(); // test3.d(22): Error: function test3.SomeData.iPlus2 () is not callable using argument types () shared } } -------- This seems like it should be legal because SomeData is a value type. Accessing _dat.i directly is legal, and _dat can't possibly be shared. If I'm understanding things correctly, transitive shared shouldn't apply to value types like this, so the type of "this" when calling iPlus2 should just be SomeData.
It can't be garantueed that a pointer to _dat is not given away at some point in the program. For example you could have a clas Foo that inherits from Bob and has a getter for _dat. Then it wouldn't be correct anymore to sasume _dat is unshared. Because of that it has been decided that trying to figure out if _dat has to be shared or not will not happen, thus its just shared always. I've already reported this some time ago and essentially it makes synchronized classes useless for me. I usually just write a normal class and but the synchronized blocks in myself. Also I use __gshared ;-) -- Kind Regards Benjamin Thaut
Oct 24 2011
On 10/25/2011 08:36 AM, Andrew Wiley wrote:On Tue, Oct 25, 2011 at 1:26 AM, Benjamin Thaut <code benjamin-thaut.de <mailto:code benjamin-thaut.de>> wrote: Am 25.10.2011 08:06, schrieb Andrew Wiley: Geez, I try to write some multithreaded code and I just keep hitting these: -------- module test3; struct SomeData { int i; int iPlus2() { return i + 2; } } synchronized class Bob { private: SomeData _dat; public: this() { _dat.i = 3; } property int i() { return _dat.iPlus2(); // test3.d(22): Error: function test3.SomeData.iPlus2 () is not callable using argument types () shared } } -------- This seems like it should be legal because SomeData is a value type. Accessing _dat.i directly is legal, and _dat can't possibly be shared. If I'm understanding things correctly, transitive shared shouldn't apply to value types like this, so the type of "this" when calling iPlus2 should just be SomeData. It can't be garantueed that a pointer to _dat is not given away at some point in the program. For example you could have a clas Foo that inherits from Bob and has a getter for _dat. Then it wouldn't be correct anymore to sasume _dat is unshared. Because of that it has been decided that trying to figure out if _dat has to be shared or not will not happen, thus its just shared always. I've already reported this some time ago and essentially it makes synchronized classes useless for me. I usually just write a normal class and but the synchronized blocks in myself. Also I use __gshared ;-) Alright, but why can I access _dat.i without synchronization?
_dat.i is shared by transitivity. You can access shared variables without synchronization (according to TDPL, memory barriers are inserted automatically, but I don't know if DMD implements this). SomeData.iPlus2's implicit 'this' parameter is not shared.
Oct 25 2011
On 10/25/2011 02:33 PM, Gor Gyolchanyan wrote:Yes. The shared-ness, const-ness or immutable-ness of the _this_ parameter is defined by marking the method itself shared, const or immutable respectively. But marking the method shared or immutable makes that method callable _ONLY_ for shared or immutable objects of that class or struct respectively. In order to make that struct usable from both shared and non-shared contexts, you need to have 2 overloads of that method: shared and non-shared.
Yes, indeed: One that is efficient and correct in an unshared context and one that _actually works_ if sharing is going on. The two D implementations are the same only in toy examples, and since memory barriers have to be inserted for the shared one, the two methods necessarily compile to different machine code.
Oct 25 2011
On 25.10.2011 18:35, Gor Gyolchanyan wrote:What? Are you sure? It's supposed to be! Sharedness of the method is the sharedness of the _this_ parameter, which must cause overloading, since shared-ness of a type is part of the type. If so, it's definitely a bug. On Tue, Oct 25, 2011 at 8:24 PM, Andrew Wiley<wiley.andrew.j gmail.com> wrote:On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> wrote:And so you can have both thread-safe synchronized heavy-duty container and a fast and small container all in one just by overloading the appropriate methods and adding appropriate synchronization blocks in the shared ones. This is one of those "little" advantages of D over C++, that make my life _SO_ much easier.
Except that overloading shared and non-shared methods is not allowed.
It works for simple cases at least: class C { int i() shared { return 1; } int i() { return 2; } } void main() { auto c1 = new C(); assert(c1.i() == 2); auto c2 = cast(shared)new C(); assert(c2.i() == 1); }
Oct 25 2011
On 10/25/2011 06:24 PM, Andrew Wiley wrote:On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyolchanyan <gor.f.gyolchanyan gmail.com <mailto:gor.f.gyolchanyan gmail.com>> wrote: And so you can have both thread-safe synchronized heavy-duty container and a fast and small container all in one just by overloading the appropriate methods and adding appropriate synchronization blocks in the shared ones. This is one of those "little" advantages of D over C++, that make my life _SO_ much easier. Except that overloading shared and non-shared methods is not allowed.
Yes it is. struct X{ string foo(){ return "unshared"; } string foo()shared{ return "shared"; } } void main(){ X x; shared X y; assert(x.foo() == "unshared"); assert(y.foo() == "shared"); }
Oct 25 2011
--20cf303bff606c2cca04b019c30b Content-Type: text/plain; charset=ISO-8859-1 On Tue, Oct 25, 2011 at 1:26 AM, Benjamin Thaut <code benjamin-thaut.de>wrote:Am 25.10.2011 08:06, schrieb Andrew Wiley: Geez, I try to write some multithreaded code and I just keep hittingthese: -------- module test3; struct SomeData { int i; int iPlus2() { return i + 2; } } synchronized class Bob { private: SomeData _dat; public: this() { _dat.i = 3; } property int i() { return _dat.iPlus2(); // test3.d(22): Error: function test3.SomeData.iPlus2 () is not callable using argument types () shared } } -------- This seems like it should be legal because SomeData is a value type. Accessing _dat.i directly is legal, and _dat can't possibly be shared. If I'm understanding things correctly, transitive shared shouldn't apply to value types like this, so the type of "this" when calling iPlus2 should just be SomeData.
It can't be garantueed that a pointer to _dat is not given away at some point in the program. For example you could have a clas Foo that inherits from Bob and has a getter for _dat. Then it wouldn't be correct anymore to sasume _dat is unshared. Because of that it has been decided that trying to figure out if _dat has to be shared or not will not happen, thus its just shared always. I've already reported this some time ago and essentially it makes synchronized classes useless for me. I usually just write a normal class and but the synchronized blocks in myself. Also I use __gshared ;-)
Alright, but why can I access _dat.i without synchronization? --20cf303bff606c2cca04b019c30b Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Tue, Oct 25, 2011 at 1:26 AM, Benjamin Thaut = <span dir=3D"ltr"><<a href=3D"mailto:code benjamin-thaut.de">code benjam= in-thaut.de</a>></span> wrote:<br><blockquote class=3D"gmail_quote" styl= e=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"> Am 25.10.2011 08:06, schrieb Andrew Wiley:<div><div></div><div class=3D"h5"=<br>
x #ccc solid;padding-left:1ex"> Geez, I try to write some multithreaded code and I just keep hitting these:= <br> --------<br> module test3;<br> <br> struct SomeData {<br> int i;<br> int iPlus2() {<br> return i + 2;<br> }<br> }<br> <br> synchronized class Bob {<br> private:<br> SomeData _dat;<br> public:<br> this() {<br> _dat.i =3D 3;<br> }<br> property<br> int i() {<br> return _dat.iPlus2(); // test3.d(22): Error: function<br> test3.SomeData.iPlus2 () is not callable using argument types () shared<br> }<br> }<br> --------<br> <br> This seems like it should be legal because SomeData is a value type.<br> Accessing _dat.i directly is legal, and _dat can't possibly be shared.<= br> If I'm understanding things correctly, transitive shared shouldn't = apply<br> to value types like this, so the type of "this" when calling iPlu= s2<br> should just be SomeData.<br> </blockquote> <br></div></div> It can't be garantueed that a pointer to _dat is not given away at some= point in the program. For example you could have a clas Foo that inherits = from Bob and has a getter for _dat. Then it wouldn't be correct anymore= to sasume _dat is unshared. Because of that it has been decided that tryin= g to figure out if _dat has to be shared or not will not happen, thus its j= ust shared always. I've already reported this some time ago and essenti= ally it makes synchronized classes useless for me. I usually just write a n= ormal class and but the synchronized blocks in myself. Also I use __gshared= ;-)</blockquote> <div><br></div><div>Alright, but why can I access _dat.i without synchroniz= ation?=A0</div></div> --20cf303bff606c2cca04b019c30b--
Oct 24 2011
Yes. The shared-ness, const-ness or immutable-ness of the _this_ parameter is defined by marking the method itself shared, const or immutable respectively. But marking the method shared or immutable makes that method callable _ONLY_ for shared or immutable objects of that class or struct respectively. In order to make that struct usable from both shared and non-shared contexts, you need to have 2 overloads of that method: shared and non-shared. On Tue, Oct 25, 2011 at 4:22 PM, Timon Gehr <timon.gehr gmx.ch> wrote:On 10/25/2011 08:36 AM, Andrew Wiley wrote:On Tue, Oct 25, 2011 at 1:26 AM, Benjamin Thaut <code benjamin-thaut.de <mailto:code benjamin-thaut.de>> wrote: =A0 =A0Am 25.10.2011 08:06, schrieb Andrew Wiley: =A0 =A0 =A0 =A0Geez, I try to write some multithreaded code and I just k=
=A0 =A0 =A0 =A0hitting these: =A0 =A0 =A0 =A0-------- =A0 =A0 =A0 =A0module test3; =A0 =A0 =A0 =A0struct SomeData { =A0 =A0 =A0 =A0int i; =A0 =A0 =A0 =A0int iPlus2() { =A0 =A0 =A0 =A0return i + 2; =A0 =A0 =A0 =A0} =A0 =A0 =A0 =A0} =A0 =A0 =A0 =A0synchronized class Bob { =A0 =A0 =A0 =A0private: =A0 =A0 =A0 =A0SomeData _dat; =A0 =A0 =A0 =A0public: =A0 =A0 =A0 =A0this() { =A0 =A0 =A0 =A0_dat.i =3D 3; =A0 =A0 =A0 =A0} =A0 =A0 =A0 =A0 property =A0 =A0 =A0 =A0int i() { =A0 =A0 =A0 =A0return _dat.iPlus2(); // test3.d(22): Error: function =A0 =A0 =A0 =A0test3.SomeData.iPlus2 () is not callable using argument t=
=A0 =A0 =A0 =A0shared =A0 =A0 =A0 =A0} =A0 =A0 =A0 =A0} =A0 =A0 =A0 =A0-------- =A0 =A0 =A0 =A0This seems like it should be legal because SomeData is a =
type. =A0 =A0 =A0 =A0Accessing _dat.i directly is legal, and _dat can't possib=
=A0 =A0 =A0 =A0shared. =A0 =A0 =A0 =A0If I'm understanding things correctly, transitive shared =A0 =A0 =A0 =A0shouldn't apply =A0 =A0 =A0 =A0to value types like this, so the type of "this" when call=
=A0 =A0 =A0 =A0should just be SomeData. =A0 =A0It can't be garantueed that a pointer to _dat is not given away a=
=A0 =A0some point in the program. For example you could have a clas Foo =A0 =A0that inherits from Bob and has a getter for _dat. Then it wouldn'=
=A0 =A0be correct anymore to sasume _dat is unshared. Because of that it =A0 =A0has been decided that trying to figure out if _dat has to be shar=
=A0 =A0or not will not happen, thus its just shared always. I've already =A0 =A0reported this some time ago and essentially it makes synchronized =A0 =A0classes useless for me. I usually just write a normal class and b=
=A0 =A0the synchronized blocks in myself. Also I use __gshared ;-) Alright, but why can I access _dat.i without synchronization?
_dat.i is shared by transitivity. You can access shared variables without synchronization (according to TDPL, memory barriers are inserted automatically, but I don't know if DMD implements this). SomeData.iPlus2'=
implicit 'this' parameter is not shared.
Oct 25 2011
And so you can have both thread-safe synchronized heavy-duty container and a fast and small container all in one just by overloading the appropriate methods and adding appropriate synchronization blocks in the shared ones. This is one of those "little" advantages of D over C++, that make my life _SO_ much easier. On Tue, Oct 25, 2011 at 4:44 PM, Timon Gehr <timon.gehr gmx.ch> wrote:On 10/25/2011 02:33 PM, Gor Gyolchanyan wrote:Yes. The shared-ness, const-ness or immutable-ness of the _this_ parameter is defined by marking the method itself shared, const or immutable respectively. But marking the method shared or immutable makes that method callable _ONLY_ for shared or immutable objects of that class or struct respectively. In order to make that struct usable from both shared and non-shared contexts, you need to have 2 overloads of that method: shared and non-shared.
Yes, indeed: One that is efficient and correct in an unshared context and one that _actually works_ if sharing is going on. The two D implementations are the same only in toy examples, and since memory barriers have to be inserted for the shared one, the two methods necessarily compile to different machine code.
Oct 25 2011
--00151773e26ea2580204b021fa02 Content-Type: text/plain; charset=ISO-8859-1 On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyolchanyan < gor.f.gyolchanyan gmail.com> wrote:And so you can have both thread-safe synchronized heavy-duty container and a fast and small container all in one just by overloading the appropriate methods and adding appropriate synchronization blocks in the shared ones. This is one of those "little" advantages of D over C++, that make my life _SO_ much easier.
--00151773e26ea2580204b021fa02 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <br><br><div class=3D"gmail_quote">On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyo= lchanyan <span dir=3D"ltr"><<a href=3D"mailto:gor.f.gyolchanyan gmail.co= m">gor.f.gyolchanyan gmail.com</a>></span> wrote:<br><blockquote class= =3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padd= ing-left:1ex;"> And so you can have both thread-safe synchronized heavy-duty container<br> and a fast and small container all in one just by overloading the<br> appropriate methods and adding appropriate synchronization blocks in<br> the shared ones.<br> This is one of those "little" advantages of D over C++, that make= my<br> life _SO_ much easier.<br> <div><div></div><div class=3D"h5"><br></div></div></blockquote><div><br></d= iv><div>Except that overloading shared and non-shared methods is not allowe= d.=A0</div></div> --00151773e26ea2580204b021fa02--
Oct 25 2011
What? Are you sure? It's supposed to be! Sharedness of the method is the sharedness of the _this_ parameter, which must cause overloading, since shared-ness of a type is part of the type. If so, it's definitely a bug. On Tue, Oct 25, 2011 at 8:24 PM, Andrew Wiley <wiley.andrew.j gmail.com> wrote:On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyolchanyan <gor.f.gyolchanyan gmail.com> wrote:And so you can have both thread-safe synchronized heavy-duty container and a fast and small container all in one just by overloading the appropriate methods and adding appropriate synchronization blocks in the shared ones. This is one of those "little" advantages of D over C++, that make my life _SO_ much easier.
Except that overloading shared and non-shared methods is not allowed.
Oct 25 2011
--00151773eb425780a604b0228fa7 Content-Type: text/plain; charset=ISO-8859-1 On Tue, Oct 25, 2011 at 11:59 AM, Timon Gehr <timon.gehr gmx.ch> wrote:On 10/25/2011 06:24 PM, Andrew Wiley wrote:On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyolchanyan <gor.f.gyolchanyan gmail.com <mailto:gor.f.gyolchanyan **gmail.com<gor.f.gyolchanyan gmail.com>>> wrote: And so you can have both thread-safe synchronized heavy-duty container and a fast and small container all in one just by overloading the appropriate methods and adding appropriate synchronization blocks in the shared ones. This is one of those "little" advantages of D over C++, that make my life _SO_ much easier. Except that overloading shared and non-shared methods is not allowed.
Yes it is. struct X{ string foo(){ return "unshared"; } string foo()shared{ return "shared"; } } void main(){ X x; shared X y; assert(x.foo() == "unshared"); assert(y.foo() == "shared"); }
Then it's been silently fixed since this was written: http://3d.benjamin-thaut.de/?p=18 --00151773eb425780a604b0228fa7 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Tue, Oct 25, 2011 at 11:59 AM, Timon Gehr <sp= an dir=3D"ltr"><<a href=3D"mailto:timon.gehr gmx.ch">timon.gehr gmx.ch</= a>></span> wrote:<br><blockquote class=3D"gmail_quote" style=3D"margin:0= 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"> <div class=3D"im">On 10/25/2011 06:24 PM, Andrew Wiley wrote:<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l= eft:1px #ccc solid;padding-left:1ex"><div class=3D"im"> <br> <br> On Tue, Oct 25, 2011 at 8:06 AM, Gor Gyolchanyan<br></div><div class=3D"im"=
gyolchanyan gmail.com</a> <mailto:<a href=3D"mailto:gor.f.gyolchanyan gm= ail.com" target=3D"_blank">gor.f.gyolchanyan <u></u>gmail.com</a>>> w= rote:<br> <br> =A0 =A0And so you can have both thread-safe synchronized heavy-duty contai= ner<br> =A0 =A0and a fast and small container all in one just by overloading the<b= r> =A0 =A0appropriate methods and adding appropriate synchronization blocks i= n<br> =A0 =A0the shared ones.<br> =A0 =A0This is one of those "little" advantages of D over C++, t= hat make my<br> =A0 =A0life _SO_ much easier.<br> <br> <br></div><div class=3D"im"> Except that overloading shared and non-shared methods is not allowed.<br> </div></blockquote> <br> Yes it is.<br> <br> struct X{<br> =A0 =A0string foo(){ return "unshared"; }<br> =A0 =A0string foo()shared{ return "shared"; }<br> }<br> <br> void main(){<br> =A0 =A0X x;<br> =A0 =A0shared X y;<br> =A0 =A0assert(x.foo() =3D=3D "unshared");<br> =A0 =A0assert(y.foo() =3D=3D "shared");<br> }<br></blockquote><div><br></div><div>Then it's been silently fixed sin= ce this was written:</div><div><a href=3D"http://3d.benjamin-thaut.de/?p=3D= 18">http://3d.benjamin-thaut.de/?p=3D18</a>=A0</div></div><br> --00151773eb425780a604b0228fa7--
Oct 25 2011









simendsjo <simendsjo gmail.com> 