Re: Different array rotation algorithms benchmark
On Thursday, 1 September 2016 at 13:16:19 UTC, Johan Engelen wrote: On Thursday, 1 September 2016 at 10:37:18 UTC, Miguel L wrote: Also, forgot to specify I am using LDC with -05. And the version of LDC too please ;-) LDC version is: ldc2-1.1.0-beta2-win64-msvc
Re: DUB, link automatically right object for platform and archi
On 02/09/2016 6:01 AM, Basile B. wrote: I've converted this section: "configurations" : [ { "name" : "nux32", "dflags" : [ "objects/coff32/beaengine.o" ] }, { "name" : "nux64", "dflags" : [ "objects/coff64/beaengine.o" ] }, { "name" : "win32", "dflags" : [ "objects\\omf32\\beaengine.obj" ] to: "buildSettings" : { "dflags-linux-x86" : ["objects/coff32/beaengine.o"], "dflags-linux-x86_64" : ["objects/coff64/beaengine.o"], "dflags-windows-x86" : ["objects\\omf32\\beaengine.obj"] }, Because previously the right config could not be selected when the package was used as dependency. But now the object is not linked in the static library produced by the project. What's wrong in my description ? Well for starters buildSettings is just a name given to a group of properties. It doesn't actually go INTO the dub file. dflags is valid in top level config, subPackage and of course configuration.
Re: Fiber cross threads terminated
On Friday, 2 September 2016 at 01:53:58 UTC, Steven Schveighoffer wrote: On 9/1/16 9:27 PM, mogu wrote: Here's my code in main function: ``` auto fiber = new Fiber({ while (true) { Thread.sleep(1.seconds); Fiber.yield; } }); void foo() { while (true) { fiber.call; //Thread.sleep(1.seconds); //"---".writeln; } } new Thread({ foo(); }).start; new Thread({ Thread.sleep(500.msecs); foo(); }).start; ``` If I comment the `fiber.call;`, all works. system: ubuntu 16.04LTS dmd version: 2.071.1 Fibers in D are not meant to be run in multiple threads. -Steve Thanks. I got it.
Re: Fiber cross threads terminated
On 9/1/16 9:27 PM, mogu wrote: Here's my code in main function: ``` auto fiber = new Fiber({ while (true) { Thread.sleep(1.seconds); Fiber.yield; } }); void foo() { while (true) { fiber.call; //Thread.sleep(1.seconds); //"---".writeln; } } new Thread({ foo(); }).start; new Thread({ Thread.sleep(500.msecs); foo(); }).start; ``` If I comment the `fiber.call;`, all works. system: ubuntu 16.04LTS dmd version: 2.071.1 Fibers in D are not meant to be run in multiple threads. -Steve
Fiber cross threads terminated
Here's my code in main function: ``` auto fiber = new Fiber({ while (true) { Thread.sleep(1.seconds); Fiber.yield; } }); void foo() { while (true) { fiber.call; //Thread.sleep(1.seconds); //"---".writeln; } } new Thread({ foo(); }).start; new Thread({ Thread.sleep(500.msecs); foo(); }).start; ``` If I comment the `fiber.call;`, all works. system: ubuntu 16.04LTS dmd version: 2.071.1
Re: Storing a reference
On Thursday, 1 September 2016 at 21:07:36 UTC, Steven Schveighoffer wrote: On 9/1/16 4:38 PM, Yuxuan Shui wrote: [...] Referring to a null object is not a problem. Your program crashes ungracefully, but does not corrupt memory. However, in either approach, it can easily end up being a dangling pointer. But to refer to a null location is quite easy: int *foo; // null ptr auto a = x(*foo); assert(&a.xa() == null); Your approach is less desirable because of the closure to point at a given reference which can be had with just a reference. Needless allocation. -Steve Makes sense. Thanks!
Re: Storing a reference
On 9/1/16 4:38 PM, Yuxuan Shui wrote: On Thursday, 1 September 2016 at 20:28:03 UTC, Rene Zwanenburg wrote: On Thursday, 1 September 2016 at 19:37:25 UTC, Yuxuan Shui wrote: [...] This will allocate a closure. A struct definition inside a function has a hidden context / closure pointer, unless it's a static struct. There is nothing like a ref variable in D. If you want to refer to something someplace else, use a pointer. You can create a pointer wrapper which acts like a reference (untested): auto toRef(ref T value) { return Ref!T(&value); } struct Ref(T) { private T* value; @property ref T _value() { return *value; } alias _value this; } Note that D's pointer syntax is a bit friendlier than C++'s: the dot operator works fine on pointers. A good reason to use the Ref wrapper is to forward arithmetic operations to the wrapped value. I think my approach is probably better, because I believe (correct me if I'm wrong): 1) it will never refer to a null object. 2) after DIP1000 is implemented we will be able to make sure there will be no dangling reference. Referring to a null object is not a problem. Your program crashes ungracefully, but does not corrupt memory. However, in either approach, it can easily end up being a dangling pointer. But to refer to a null location is quite easy: int *foo; // null ptr auto a = x(*foo); assert(&a.xa() == null); Your approach is less desirable because of the closure to point at a given reference which can be had with just a reference. Needless allocation. -Steve
Re: Storing a reference
On Thursday, 1 September 2016 at 20:38:13 UTC, Yuxuan Shui wrote: I think my approach is probably better, because I believe (correct me if I'm wrong): 1) it will never refer to a null object. That's true, but you can ensure the same thing for the wrapper: struct Ref() { @disable this(); this(T* value) { assert(value !is null); this.value = value; } // rest same as before } 2) after DIP1000 is implemented we will be able to make sure there will be no dangling reference. I'm not very familiar with the details of DIP1000, so I can't comment on that.
Re: DUB, link automatically right object for platform and archi
On Thursday, 1 September 2016 at 18:01:19 UTC, Basile B. wrote: I've converted this section: [...] to: "buildSettings" : { "dflags-linux-x86" : ["objects/coff32/beaengine.o"], "dflags-linux-x86_64" : ["objects/coff64/beaengine.o"], "dflags-windows-x86" : ["objects\\omf32\\beaengine.obj"] }, Because previously the right config could not be selected when the package was used as dependency. But now the object is not linked in the static library produced by the project. What's wrong in my description ? neither dflags, lflags nor sourceFiles work. Strangely enough this new section is completely missing in the dub.json obtained after the dub fetch.
Re: Storing a reference
On Thursday, 1 September 2016 at 20:28:03 UTC, Rene Zwanenburg wrote: On Thursday, 1 September 2016 at 19:37:25 UTC, Yuxuan Shui wrote: [...] This will allocate a closure. A struct definition inside a function has a hidden context / closure pointer, unless it's a static struct. There is nothing like a ref variable in D. If you want to refer to something someplace else, use a pointer. You can create a pointer wrapper which acts like a reference (untested): auto toRef(ref T value) { return Ref!T(&value); } struct Ref(T) { private T* value; @property ref T _value() { return *value; } alias _value this; } Note that D's pointer syntax is a bit friendlier than C++'s: the dot operator works fine on pointers. A good reason to use the Ref wrapper is to forward arithmetic operations to the wrapped value. I think my approach is probably better, because I believe (correct me if I'm wrong): 1) it will never refer to a null object. 2) after DIP1000 is implemented we will be able to make sure there will be no dangling reference.
Re: Storing a reference
On Thursday, 1 September 2016 at 19:37:25 UTC, Yuxuan Shui wrote: I just figured out how to store a reference: @safe: auto x(ref int a) { struct A { ref int xa() { return a; } } return A(); } void main() { import std.stdio; int b = 10; auto a = x(b); a.xa = 20; writeln(b); //Prints 20 } I have no idea if this is a right thing to do. Can someone tell me if this is idiomatic D, and whether there're any catches to this method or not? Thanks. This will allocate a closure. A struct definition inside a function has a hidden context / closure pointer, unless it's a static struct. There is nothing like a ref variable in D. If you want to refer to something someplace else, use a pointer. You can create a pointer wrapper which acts like a reference (untested): auto toRef(ref T value) { return Ref!T(&value); } struct Ref(T) { private T* value; @property ref T _value() { return *value; } alias _value this; } Note that D's pointer syntax is a bit friendlier than C++'s: the dot operator works fine on pointers. A good reason to use the Ref wrapper is to forward arithmetic operations to the wrapped value.
Storing a reference
I just figured out how to store a reference: @safe: auto x(ref int a) { struct A { ref int xa() { return a; } } return A(); } void main() { import std.stdio; int b = 10; auto a = x(b); a.xa = 20; writeln(b); //Prints 20 } I have no idea if this is a right thing to do. Can someone tell me if this is idiomatic D, and whether there're any catches to this method or not? Thanks.
DUB, link automatically right object for platform and archi
I've converted this section: "configurations" : [ { "name" : "nux32", "dflags" : [ "objects/coff32/beaengine.o" ] }, { "name" : "nux64", "dflags" : [ "objects/coff64/beaengine.o" ] }, { "name" : "win32", "dflags" : [ "objects\\omf32\\beaengine.obj" ] to: "buildSettings" : { "dflags-linux-x86" : ["objects/coff32/beaengine.o"], "dflags-linux-x86_64" : ["objects/coff64/beaengine.o"], "dflags-windows-x86" : ["objects\\omf32\\beaengine.obj"] }, Because previously the right config could not be selected when the package was used as dependency. But now the object is not linked in the static library produced by the project. What's wrong in my description ?
Re: traits.d: error: forward reference of variable parentPrefix
nvm. Renaming the MyDigestWrapper import caused the error.
Re: Error when running vibe.d example application, not sure of the cause.
On Thursday, 1 September 2016 at 09:37:22 UTC, Kagamin wrote: Probably LDC issue https://github.com/ldc-developers/ldc/issues Thank you for your reply. I built LDC (version 1.1.0 beta 2) from source and ran dub using: $ dub run --compiler="~/Downloads/ldc/bin/ldc2" And everything works now, so it must have been. I looked through some of the issues and it surprises me that I was the only one having this problem, but it must have been fixed at some point. Anyway, thanks for your time, I feel a bit silly now :)
Re: About spinlock implementation
On Thursday, 1 September 2016 at 10:38:07 UTC, qznc wrote: On Thursday, 1 September 2016 at 10:30:12 UTC, Guillaume Piolat wrote: On Thursday, 1 September 2016 at 07:46:04 UTC, qznc wrote: I find the documentation on MemoryOrder lacking about the semantics of rel. :( [0] https://dlang.org/library/core/atomic/memory_order.html What helped me was to read std::memory_order documentation http://en.cppreference.com/w/cpp/atomic/memory_order Yes, but how do they map? Is D's rel = relaxed or release or acq_rel? Also, reading C++ documentation should not be required of course. ;) MemoryOrder.rel must be std::memory_order::release (70% confidence) And std::memory_order::relaxed is MemoryOrder.raw of course (90% confidence).
traits.d: error: forward reference of variable parentPrefix
Hello all, I'm trying to use a std.digest, namely MD5 and sHA, as a template parameter like so: auto x = new MyDigestWrapper!MD5; The compiler (dmd2) then throws two error messages at me which puzzle me. phobos/std/traits.d 554: Error: forward reference of variable parentPrefix, and phobos/std/traits.d 727: Error: template instance std.traits.fqnSym!(const(MyDigestWrapper!(MD5))) error instantiating ...std/traits.d 462: inst. from here: fqn!Type(const(MyDigestWrapper!(MD5)), false, false, false, false) mydigestwrapper.d-mixin-283 310: inst. from here: fullyQualifiedName!(const(MyDigestWrapper!(MD5))) app.d 211: inst. from here MyDigestWrapper!(MD5) 1. What's going on ? 2. How is that fqnSym involved ? 3. What is parentPrefix ? 4. What is this forward ref, and why ? 5. How can I review mydigestwrapper.d-mixin-283 ? Thanks for your time
Re: Different array rotation algorithms benchmark
On Thursday, 1 September 2016 at 10:37:18 UTC, Miguel L wrote: Also, forgot to specify I am using LDC with -05. And the version of LDC too please ;-)
Re: Overriding abstract class fields
On Thursday, 1 September 2016 at 11:34:28 UTC, Basile B. wrote: On Thursday, 1 September 2016 at 11:09:18 UTC, slaid wrote: I have a snippet: How do I override this height field? Thanks The field height is not overridden. In C you have two "height". Since your array is of type A[], map takes A.height. Only methods are virtual. To solve the problem you can create a virtual getter: But since height is only a field you can just use the same variable and set the value in the constructor (for example) Just what I needed, thanks a bunch!
Re: Overriding abstract class fields
On Thursday, 1 September 2016 at 11:09:18 UTC, slaid wrote: I have a snippet: How do I override this height field? Thanks The field height is not overridden. In C you have two "height". Since your array is of type A[], map takes A.height. abstract class A { int height = 0; } class B : A {} class C : A { int height = 1; } void main() { writeln((new C).height); // prints 0, the height of C writeln((cast(A)(new C).height); // prints 1, the height of A } Only methods are virtual. To solve the problem you can create a virtual getter: °° abstract class A { int height(); } class B : A { override int height(){return 0;} } class C : A { override int height(){return 1;} } °° But since height is only a field you can just use the same variable and set the value in the constructor (for example) °° abstract class A { int height; } class B : A { this(){height = 0;} } class C : A { this(){height = 1;} } °°
Re: testing for deprecation
On 01/09/2016 11:11 PM, Cauterite wrote: How does one test whether a symbol is deprecated? I would have expected something like: __traits(isDeprecated, foo). In the compiler we have Dsymbol.isDeprecated, is that not accessible in any way from code? The only solution I can think of is compiling with -de and using __traits(compiles, {alias x = foo;}) which actually does seem to work. Pretty lousy though. That is a first that somebody wanted it. Bug report please!
testing for deprecation
How does one test whether a symbol is deprecated? I would have expected something like: __traits(isDeprecated, foo). In the compiler we have Dsymbol.isDeprecated, is that not accessible in any way from code? The only solution I can think of is compiling with -de and using __traits(compiles, {alias x = foo;}) which actually does seem to work. Pretty lousy though.
Overriding abstract class fields
I have a snippet: import std.stdio; import std.algorithm; abstract class A { int height = 0; } class B : A { } class C : A { int height = 1; } void main() { A[][int] list; list[0] = new A[](0); list[0] ~= new B(); list[0] ~= new C(); list[0] ~= new B(); writeln(list[0].map!(x=>x.height)); } The output of this is [0, 0, 0] when if height was overridden it should print [0, 1, 0]. This is a trivial case for simplicity of the question, but in my actual code, I am trying to use the height field for sorting the A[] list (or reducing with max to get the object with the max height), but since they're all 0, none of the sorting occurs. How do I override this height field? Thanks
Re: About spinlock implementation
On Thursday, 1 September 2016 at 10:30:12 UTC, Guillaume Piolat wrote: On Thursday, 1 September 2016 at 07:46:04 UTC, qznc wrote: I find the documentation on MemoryOrder lacking about the semantics of rel. :( [0] https://dlang.org/library/core/atomic/memory_order.html What helped me was to read std::memory_order documentation http://en.cppreference.com/w/cpp/atomic/memory_order Yes, but how do they map? Is D's rel = relaxed or release or acq_rel? Also, reading C++ documentation should not be required of course. ;)
Re: Different array rotation algorithms benchmark
On Thursday, 1 September 2016 at 09:53:59 UTC, Miguel L wrote: On Thursday, 1 September 2016 at 09:36:16 UTC, Miguel L wrote: Hi I recently needed a very optimized array rotation algorithm, so I did this benchmark, hope you find it interesting. I am a bit surprised by the poor results of std.algorithm.bringToFront: [...] Sorry Rotate4 had a bug, there was an extra for that was not neccesary, this is the correct implementation: void Rotate4(T)(T[] input, long n) pure { /* 1,2,3,4,5,6,7,8 - 2 - * 7,2,3,4,5,6,1,8 - a=0 b=8-2=6 * 7,8,3,4,5,6,1,2 - a=1 b=7 * 7,8,1,4,5,6,3,2 - a=2 b=6 * 7,8,1,2,5,6,3,4 - a=3 b=7 * 7,8,1,2,3,6,5,4 - a=4 b=6 * 7,8,1,2,3,4,5,6 - a=5 b=7 1,2,3,4,5,6,7,8,9 - 3 - * 7,2,3,4,5,6,1,8,9 - a=0 b=9-3=6 * 7,8,3,4,5,6,1,2,9 - a=1 b=7 * 7,8,9,4,5,6,1,2,3 - a=2 b=8 * 7,8,9,1,5,6,4,2,3 - a=3 b=6 * 7,8,9,1,2,6,4,5,3 - a=4 b=7 * 7,8,9,1,2,3,4,5,6 - a=5 b=8 */ if(n<0) n=input.length+n; long a=0,b=input.length-n; T tmp; while(a=input.length) { b=input.length-n; } } } Very sorry again: Rotate4 was not correct with negative offsets. This implementation works correctly: void Rotar4(T)(T[] input, long n) pure { /* 1,2,3,4,5,6,7,8 - 2 - * 7,2,3,4,5,6,1,8 - a=0 b=8-2=6 * 7,8,3,4,5,6,1,2 - a=1 b=7 * 7,8,1,4,5,6,3,2 - a=2 b=6 * 7,8,1,2,5,6,3,4 - a=3 b=7 * 7,8,1,2,3,6,5,4 - a=4 b=6 * 7,8,1,2,3,4,5,6 - a=5 b=7 * * 1,2,3,4,5,6,7,8 - -2 - * 1,8,3,4,5,6,7,2 - a=7 b=1 * 7,8,3,4,5,6,1,2 - a=6 b=0 * 7,6,3,4,5,8,1,2 - a=5 b=1 * 5,6,3,4,7,8,3,4 - a=4 b=0 * 3,6,5,4,7,8,1,2 - a=3 b=1 * 3,4,5,6,7,8,1,2 - a=2 b=0 1,2,3,4,5,6,7,8,9 - 2 - * 7,2,3,4,5,6,1,8,9 - a=0 b=9-3=6 * 7,8,3,4,5,6,1,2,9 - a=1 b=7 * 7,8,9,4,5,6,1,2,3 - a=2 b=8 * 7,8,9,1,5,6,4,2,3 - a=3 b=6 * 7,8,9,1,2,6,4,5,3 - a=4 b=7 * 7,8,9,1,2,3,4,5,6 - a=5 b=8 */ long a,b; T tmp; if(n>0) { a=0; b=input.length-n; while(a=input.length) b=input.length-n; } } else { a=input.length-1; long b0=-n-1; b=b0; while(a>=-n) { tmp=input[b]; input[b]=input[a]; input[a]=tmp; --a; --b; if(b<0) b=b0; } } } Also, forgot to specify I am using LDC with -05. Updated benchmark results: Rotate0: 0.344186s Rotate1: 1.76369s Rotate2: 0.169968s Rotate3: 0.354091s Rotate4: 0.156231s
Re: About spinlock implementation
On Thursday, 1 September 2016 at 07:46:04 UTC, qznc wrote: I find the documentation on MemoryOrder lacking about the semantics of rel. :( [0] https://dlang.org/library/core/atomic/memory_order.html What helped me was to read std::memory_order documentation http://en.cppreference.com/w/cpp/atomic/memory_order
Re: Different array rotation algorithms benchmark
On Thursday, 1 September 2016 at 09:36:16 UTC, Miguel L wrote: Hi I recently needed a very optimized array rotation algorithm, so I did this benchmark, hope you find it interesting. I am a bit surprised by the poor results of std.algorithm.bringToFront: [...] Sorry Rotate4 had a bug, there was an extra for that was not neccesary, this is the correct implementation: void Rotate4(T)(T[] input, long n) pure { /* 1,2,3,4,5,6,7,8 - 2 - * 7,2,3,4,5,6,1,8 - a=0 b=8-2=6 * 7,8,3,4,5,6,1,2 - a=1 b=7 * 7,8,1,4,5,6,3,2 - a=2 b=6 * 7,8,1,2,5,6,3,4 - a=3 b=7 * 7,8,1,2,3,6,5,4 - a=4 b=6 * 7,8,1,2,3,4,5,6 - a=5 b=7 1,2,3,4,5,6,7,8,9 - 3 - * 7,2,3,4,5,6,1,8,9 - a=0 b=9-3=6 * 7,8,3,4,5,6,1,2,9 - a=1 b=7 * 7,8,9,4,5,6,1,2,3 - a=2 b=8 * 7,8,9,1,5,6,4,2,3 - a=3 b=6 * 7,8,9,1,2,6,4,5,3 - a=4 b=7 * 7,8,9,1,2,3,4,5,6 - a=5 b=8 */ if(n<0) n=input.length+n; long a=0,b=input.length-n; T tmp; while(a=input.length) { b=input.length-n; } } }
Re: Error when running vibe.d example application, not sure of the cause.
Probably LDC issue https://github.com/ldc-developers/ldc/issues
Different array rotation algorithms benchmark
Hi I recently needed a very optimized array rotation algorithm, so I did this benchmark, hope you find it interesting. I am a bit surprised by the poor results of std.algorithm.bringToFront: These are the different algorithms: void Rotate0(T)(T[] input, int n) pure { if(n>0)input=input[($-n)..$]~input[0..($-n)]; if(n<0)input=input[(-n)..$]~input[0..(-n)]; } void Rotate(T)(T[] input, int n) pure { if(n>0) std.algorithm.bringToFront(input[0..($-n)],input[($-n)..$]); else if(n<0) std.algorithm.bringToFront(input[0..(-n)],input[(-n)..$]); } void reverse(T)(T[] a, long sz) pure { long i, j; for (i = 0, j = sz; i < j; ++i, --j) { T tmp = a[i]; a[i] = a[j]; a[j] = tmp; } } void Rotate2(T)(T[] array, long amt) pure { /* the algorithm from Jon Bentley's book, "Programming Pearls 2nd Edition" O(n) time and no extra memory usage (since array was specified), */ if (amt < 0) amt = array.length + amt; reverse(array, array.length-amt-1); reverse(array[array.length-amt..$], amt-1); reverse(array, array.length-1); } void Rotate3(T)(T[] input, long n) pure { if(n<0) n=input.length+n; auto tmp=input[($-n)..$].dup; for(auto j=input.length-1;j>=n;--j) input[j]=input[j-n]; input[0..n]=tmp; } void Rotate4(T)(T[] input, long n) pure //No extra memory, just swapping of elements { /* 1,2,3,4,5,6,7,8 - 2 - * 7,2,3,4,5,6,1,8 - a=0 b=8-2=6 * 7,8,3,4,5,6,1,2 - a=1 b=7 * 7,8,1,4,5,6,3,2 - a=2 b=6 * 7,8,1,2,5,6,3,4 - a=3 b=7 * 7,8,1,2,3,6,5,4 - a=4 b=6 * 7,8,1,2,3,4,5,6 - a=5 b=7 1,2,3,4,5,6,7,8,9 - 2 - * 7,2,3,4,5,6,1,8,9 - a=0 b=9-3=6 * 7,8,3,4,5,6,1,2,9 - a=1 b=7 * 7,8,9,4,5,6,1,2,3 - a=2 b=8 * 7,8,9,1,5,6,4,2,3 - a=3 b=6 * 7,8,9,1,2,6,4,5,3 - a=4 b=7 * 7,8,9,1,2,3,4,5,6 - a=5 b=8 */ if(n<0) n=input.length+n; long a=0,b=input.length-n; T tmp; while(a=input.length) { b=input.length-n; } } } This is the times I got for 400 iterations of each rotating an array of 29 elements 2 positions(200 iterations to the left, and 200 iterations to the right). Rotate0: 0.300493s Rotate1: 1.60528s Rotate2: 0.145162s Rotate3: 0.337595s Rotate4: 0.0853269s This is the test/benchmark function code, sorry for the long asserts. void RotateBenchmark() { int[] a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]; Rotate0(a,2); assert(a==[29,30,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28]); Rotate0(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); Rotate1(a,2); assert(a==[29,30,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28]); Rotate1(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); Rotate2(a,2); assert(a==[29,30,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28]); Rotate2(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); Rotate3(a,2); assert(a==[29,30,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28]); Rotate3(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); Rotate4(a,2); assert(a==[29,30,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28]); Rotate4(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); auto init1 = TickDuration.currSystemTick(); for(auto i=0;i<200;++i) Rotate0(a,2); for(auto i=0;i<200;++i) Rotate0(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); writeln("Rotate0: ",(TickDuration.currSystemTick() - init1).to!("seconds",float),"s"); init1 = TickDuration.currSystemTick(); for(auto i=0;i<200;++i) Rotate1(a,2); for(auto i=0;i<200;++i) Rotate1(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]); writeln("Rotate1: ",(TickDuration.currSystemTick() - init1).to!("seconds",float),"s"); init1 = TickDuration.currSystemTick(); for(auto i=0;i<200;++i) Rotate2(a,2); for(auto i=0;i<200;++i) Rotate2(a,-2); assert(a==[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
Re: About spinlock implementation
On Thursday, 1 September 2016 at 07:46:04 UTC, qznc wrote: This effectively makes the access to the protected value unprotected and nullifies the effect of the spinlock. So the cas operation implicit an MemoryOrder.acq? Does it make any other MemoryOrder guarantee?
Re: About spinlock implementation
On Thursday, 1 September 2016 at 07:46:04 UTC, qznc wrote: I'm not sure I understand rel [0], but raw is too weak. Raw means no sequencing barrier, so local_var = protected_value; spinlock.unlock(); could be transformed (by compiler or CPU) to spinlock.unlock(); local_var = protected_value; This effectively makes the access to the protected value unprotected and nullifies the effect of the spinlock. I find the documentation on MemoryOrder lacking about the semantics of rel. :( [0] https://dlang.org/library/core/atomic/memory_order.html Thanks very much. I finally got it. :)
Re: About spinlock implementation
On Thursday, 1 September 2016 at 06:44:13 UTC, mogu wrote: I found an implementation of spinlock in concurrency.d. ``` static shared struct SpinLock { void lock() { while (!cas(&locked, false, true)) { Thread.yield(); } } void unlock() { atomicStore!(MemoryOrder.rel)(locked, false); } bool locked; } ``` Why atomicStore use MemoryOrder.rel instead of MemoryOrder.raw? I'm not sure I understand rel [0], but raw is too weak. Raw means no sequencing barrier, so local_var = protected_value; spinlock.unlock(); could be transformed (by compiler or CPU) to spinlock.unlock(); local_var = protected_value; This effectively makes the access to the protected value unprotected and nullifies the effect of the spinlock. I find the documentation on MemoryOrder lacking about the semantics of rel. :( [0] https://dlang.org/library/core/atomic/memory_order.html